├── .babelrc
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── LICENSE
├── README.md
├── RNCommon.podspec
├── android
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kajoo
│ │ └── reactnativecommon
│ │ ├── highlighterview
│ │ ├── HighlightFrame.java
│ │ ├── HighlightViewTagParams.java
│ │ ├── HighlighterView.java
│ │ ├── HighlighterViewManager.java
│ │ ├── HighlighterViewPackage.java
│ │ ├── ReactHacks.java
│ │ ├── ReflectionUtils.java
│ │ └── UiUtils.java
│ │ ├── textinput
│ │ ├── DefaultKeyListener.java
│ │ ├── KeyListenerProxy.java
│ │ ├── TextInputDelKeyHandlerModule.java
│ │ ├── TextInputDelKeyHandlerPackage.java
│ │ └── ViewUtils.java
│ │ └── wheelpicker
│ │ ├── WheelPicker.java
│ │ ├── WheelPickerManager.java
│ │ └── WheelPickerPackage.java
│ └── res
│ ├── layout
│ └── wheel_picker.xml
│ └── values
│ ├── colors.xml
│ └── styles.xml
├── default_installation.md
├── example
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── App.js
├── __tests__
│ └── App-test.js
├── android
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── build_defs.bzl
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── keystores
│ │ ├── BUCK
│ │ └── debug.keystore.properties
│ └── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
│ ├── example-tvOS
│ │ └── Info.plist
│ ├── example-tvOSTests
│ │ └── Info.plist
│ ├── example.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ ├── example-tvOS.xcscheme
│ │ │ └── example.xcscheme
│ ├── example
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ └── main.m
│ └── exampleTests
│ │ ├── Info.plist
│ │ └── exampleTests.m
├── metro.config.js
├── package.json
└── yarn.lock
├── ios
├── RNCommon.xcodeproj
│ └── project.pbxproj
└── reactnativecommon
│ ├── highlighterview
│ ├── HighlighterView.h
│ ├── HighlighterView.m
│ ├── HighlighterViewManager.h
│ └── HighlighterViewManager.m
│ └── safearea
│ ├── SafeAreaManager.h
│ ├── SafeAreaManager.m
│ ├── SafeAreaSpacerShadowView.h
│ ├── SafeAreaSpacerShadowView.m
│ ├── SafeAreaSpacerView.h
│ ├── SafeAreaSpacerView.m
│ ├── SafeAreaSpacerViewLocalData.h
│ ├── SafeAreaSpacerViewLocalData.m
│ ├── SafeAreaSpacerViewManager.h
│ └── SafeAreaSpacerViewManager.m
├── jest-setup.js
├── jsconfig.json
├── package.json
├── scripts
├── build-ts.sh
└── build-typings.sh
├── simple.sh
├── src
├── assets
│ ├── emojis
│ │ └── index.js
│ ├── icons
│ │ ├── check-small.png
│ │ ├── check-small@2x.png
│ │ ├── check-small@3x.png
│ │ ├── check.png
│ │ ├── check@1.5x.png
│ │ ├── check@2x.png
│ │ ├── check@3x.png
│ │ ├── check@4x.png
│ │ ├── index.js
│ │ ├── search.png
│ │ ├── search@1.5x.png
│ │ ├── search@2x.png
│ │ ├── search@3x.png
│ │ ├── search@4x.png
│ │ ├── x.png
│ │ ├── x@2x.png
│ │ └── x@3x.png
│ └── index.js
├── components
│ ├── Colors.js
│ ├── LoadingView.js
│ ├── RGFText.js
│ ├── SettingsList.js
│ ├── connection
│ │ ├── __test__
│ │ │ └── index.spec.js
│ │ └── index.js
│ ├── containers
│ │ ├── ListContainer.js
│ │ ├── PageContainer.js
│ │ └── index.js
│ ├── header
│ │ ├── ItemWrapper.js
│ │ └── index.js
│ ├── images
│ │ ├── AnimatedImage.js
│ │ ├── Image.js
│ │ ├── NetworkImage.js
│ │ ├── __test__
│ │ │ └── Image.spec.js
│ │ └── index.js
│ ├── img
│ │ ├── add@2x.png
│ │ ├── disclosure.png
│ │ ├── disclosure@2x.png
│ │ ├── disclosure@3x.png
│ │ ├── filter.png
│ │ ├── filter@2x.png
│ │ ├── filter@3x.png
│ │ ├── hamburger-unread.png
│ │ ├── hamburger-unread@2x.png
│ │ ├── hamburger-unread@3x.png
│ │ ├── hamburger.png
│ │ ├── hamburger@2x.png
│ │ └── hamburger@3x.png
│ ├── index.js
│ ├── inputs
│ │ ├── BaseInput.js
│ │ ├── TagsInput.js
│ │ ├── TextArea.js
│ │ ├── TextField.js
│ │ ├── TextInput.js
│ │ ├── __test__
│ │ │ ├── TagsInput.spec.js
│ │ │ └── TextField.spec.js
│ │ └── index.js
│ ├── loading
│ │ └── index.js
│ ├── multiple-shadow
│ │ └── index.js
│ ├── nav-icons
│ │ ├── BackIcon.js
│ │ ├── BackWhiteIcon.js
│ │ ├── ForwardIcon.js
│ │ ├── ForwardWhiteIcon.js
│ │ ├── XIcon.js
│ │ ├── XWhiteIcon.js
│ │ ├── img
│ │ │ ├── back.android.png
│ │ │ ├── back.ios.png
│ │ │ ├── back@2x.android.png
│ │ │ ├── back@2x.ios.png
│ │ │ ├── back@3x.android.png
│ │ │ ├── back@3x.ios.png
│ │ │ ├── back_white.android.png
│ │ │ ├── back_white.ios.png
│ │ │ ├── back_white@2x.android.png
│ │ │ ├── back_white@2x.ios.png
│ │ │ ├── back_white@3x.android.png
│ │ │ ├── back_white@3x.ios.png
│ │ │ ├── forward.android.png
│ │ │ ├── forward.ios.png
│ │ │ ├── forward@2x.android.png
│ │ │ ├── forward@2x.ios.png
│ │ │ ├── forward@3x.android.png
│ │ │ ├── forward@3x.ios.png
│ │ │ ├── forward_white.android.png
│ │ │ ├── forward_white.ios.png
│ │ │ ├── forward_white@2x.android.png
│ │ │ ├── forward_white@2x.ios.png
│ │ │ ├── forward_white@3x.android.png
│ │ │ ├── forward_white@3x.ios.png
│ │ │ ├── x-white.png
│ │ │ ├── x-white@2x.png
│ │ │ ├── x-white@3x.png
│ │ │ ├── x.png
│ │ │ ├── x@2x.png
│ │ │ └── x@3x.png
│ │ └── index.js
│ ├── other
│ │ ├── InfiniteScrollView.js
│ │ ├── ItemsWithSeparator.js
│ │ ├── KeyboardSpacer.js
│ │ ├── PageControl.js
│ │ ├── Popover.js
│ │ ├── PureListView.js
│ │ ├── SegmentedControl.js
│ │ └── StyleSheet.js
│ ├── picker
│ │ ├── NativePicker.js
│ │ ├── PickerDialog.android.js
│ │ ├── PickerDialog.ios.js
│ │ ├── PickerItem.js
│ │ ├── PickerModal.js
│ │ ├── PickerPresenter.js
│ │ ├── __test__
│ │ │ ├── PickerPresenter.spec.js
│ │ │ └── index.spec.js
│ │ └── index.js
│ └── touchables
│ │ ├── Touchable.js
│ │ └── index.js
├── index.js
└── style
│ ├── BorderRadiuses.js
│ ├── Colors.js
│ ├── ColorsPalette.js
│ ├── Shadows.js
│ ├── Spacings.js
│ ├── ThemeManager.js
│ ├── Typography.js
│ └── index.js
└── tsconfig.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/**
2 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'eslint-config-kajoo',
3 | // "globals": {
4 | // "__DEV__": true,
5 | // "__dirname": false,
6 | // "console": false,
7 | // "document": false,
8 | // "jest": false,
9 | // "Map": true,
10 | // "Promise": true,
11 | // "Set": true,
12 | //
13 | // // Flow global types.
14 | // "ReactElement": false,
15 | // },
16 | rules: {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
50 |
51 | fastlane/report.xml
52 | fastlane/Preview.html
53 | fastlane/screenshots
54 |
55 | # Custom
56 | package-lock.json
57 | dist-ts/
58 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | example/
3 | docs/
4 | .travis.yml
5 | npm-debug.log
6 | package-lock.json
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "10"
4 | cache:
5 | yarn: true
6 | directories:
7 | - node_modules
8 | branches:
9 | only:
10 | - master
11 | install:
12 | - yarn
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2016 Reza Ghorbani Farid
5 | Copyright for portions of project react-native-common are held by WIX 2017 as part of project react-native-ui-lib. All other copyright for project react-native-common are held by Reza Ghorbani Farid, 2016.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | React Native Common
4 |
5 |
6 |
7 | Cross Platform React Native UI Toolkit & API
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## Get Started
23 |
24 | ### Installation
25 |
26 | `$ yarn add react-native-common`
27 |
28 | or
29 |
30 | `$ npm install react-native-common --save`
31 |
32 | ## Native Dependencies
33 | Some of the components are using these native dependencies, they are not a requirement but will allow you to create
34 | better lookings apps :)
35 |
36 | * react-native-animatable
37 | * react-native-blur
38 |
39 | ## Usage
40 |
41 | ```javascript
42 | import { Button } from 'react-native-common';
43 |
44 |
50 | ```
51 |
52 | ## Components Included
53 |
54 | - [x] Theming & Default Styles of the Components
55 | - [x] Badge
56 | - [x] Button
57 | - [x] Carousel
58 | - [x] Connection Status Bar
59 | - [x] DrawerLayout
60 | - [x] KeyboardSpacer
61 | - [x] Header
62 | - [x] PageControl
63 | - [x] Popover
64 | - [x] PureListView
65 | - [x] LoadingView
66 | - [x] Text
67 | - [x] TextInput
68 | - [x] MaskedInput
69 | - [x] TagsInput
70 | - [x] SegmentedControl
71 | - [x] AnimatedImage
72 | - [x] NetworkImage
73 | - [x] SettingsList
74 | - [x] SettingsList.Header
75 | - [x] SettingsList.Item
76 | - [x] StyleSheet
77 | - [x] ViewPager
78 |
79 | ## Documentation
80 |
81 | [View the full docs here](https://rghorbani.github.io/react-native-common/)
82 |
83 | ## Roadmap
84 |
85 | #### FIRST CONTRIBUTORS
86 | Look for the label `Good First Task` on the issues. Click [here](https://github.com/rghorbani/react-native-common/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Task%22) to see them.
87 |
88 | #### NOT STARTED
89 | - [ ] Add Image Component which supports parallax
90 | - [ ] Compatibility with react-native-windows
91 | - [ ] Something you's like to see? Submit an [issue](https://github.com/rghorbani/react-native-common/issues/new) or a [pull request](https://github.com/rghorbani/react-native-common/pulls)
92 |
93 | ## Contributing
94 |
95 | Interested in contributing to this repo? Have a look at our [Contributing Guide](https://github.com/rghorbani/react-native-common/blob/master/.github/CONTRIBUTING.MD)
96 |
97 | ## Related Projects
98 |
99 | #### [react-native-general-calendars](https://github.com/rghorbani/react-native-general-calendars)
100 | A `react-native` component with support of gregorian, jalaali and hijri calendar to select and work with date and time, created by [@rghorbani](https://github.com/rghorbani).
101 |
--------------------------------------------------------------------------------
/RNCommon.podspec:
--------------------------------------------------------------------------------
1 | require "json"
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "RNCommon"
7 | s.version = package["version"]
8 | s.summary = "UI & API Components Library for React Native"
9 | s.homepage = "https://github.com/rghorbani/react-native-common"
10 | s.license = "MIT"
11 | s.author = { "Reza Ghorbani" => "r.ghorbani.f@gmail.com" }
12 | s.platform = :ios, "8.0"
13 | s.source = { :git => "https://github.com/rghorbani/react-native-common.git", :tag => "master" }
14 |
15 | s.source_files = "ios/**/*.{h,m}"
16 |
17 | s.dependency "React"
18 | end
19 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | apply plugin: 'com.android.library'
3 |
4 | android {
5 | compileSdkVersion 23
6 | buildToolsVersion "23.0.1"
7 |
8 | defaultConfig {
9 | minSdkVersion 16
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile 'com.facebook.react:react-native:+'
24 | }
25 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/HighlightFrame.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import android.content.res.Resources;
5 | import android.graphics.RectF;
6 |
7 | import com.facebook.react.bridge.ReadableMap;
8 |
9 | public class HighlightFrame {
10 | public float x;
11 | public float y;
12 | public float width;
13 | public float height;
14 |
15 | public HighlightFrame(Resources resources, ReadableMap highlightFrameMap) {
16 | if (highlightFrameMap != null) {
17 | x = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("x"));
18 | y = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("y"));
19 | width = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("width"));
20 | height = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("height"));
21 | }
22 | }
23 |
24 | public HighlightFrame(float x, float y, float width, float height) {
25 | this.x = x;
26 | this.y = y;
27 | this.width = width;
28 | this.height = height;
29 | }
30 |
31 | public RectF toRect() {
32 | return new RectF(x, y, x + width,y + height);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/HighlightViewTagParams.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import android.content.res.Resources;
5 |
6 | import com.facebook.react.bridge.ReadableMap;
7 | import com.facebook.react.bridge.ReadableType;
8 |
9 | public class HighlightViewTagParams {
10 | public float paddingTop = 0;
11 | public float paddingLeft = 0;
12 | public float paddingBottom = 0;
13 | public float paddingRight = 0;
14 | public float offsetX = 0;
15 | public float offsetY = 0;
16 |
17 | public HighlightViewTagParams(Resources resources, ReadableMap highlightViewTagParams) {
18 | if (highlightViewTagParams != null) {
19 | if (highlightViewTagParams.hasKey("padding")) {
20 | if (highlightViewTagParams.getType("padding") == ReadableType.Number) {
21 | float paddingValue = UiUtils.pxToDp(resources, highlightViewTagParams.getDouble("padding"));
22 | paddingTop = paddingLeft = paddingBottom = paddingRight = paddingValue;
23 | } else if (highlightViewTagParams.getType("padding") == ReadableType.Map) {
24 | ReadableMap paddingMap = highlightViewTagParams.getMap("padding");
25 | if (paddingMap.hasKey("top")) {
26 | paddingTop = UiUtils.pxToDp(resources, paddingMap.getDouble("top"));
27 | }
28 | if (paddingMap.hasKey("left")) {
29 | paddingLeft = UiUtils.pxToDp(resources, paddingMap.getDouble("left"));
30 | }
31 | if (paddingMap.hasKey("bottom")) {
32 | paddingBottom = UiUtils.pxToDp(resources, paddingMap.getDouble("bottom"));
33 | }
34 | if (paddingMap.hasKey("right")) {
35 | paddingRight = UiUtils.pxToDp(resources, paddingMap.getDouble("right"));
36 | }
37 | }
38 | }
39 |
40 | if (highlightViewTagParams.hasKey("offset")) {
41 | ReadableMap offsetMap = highlightViewTagParams.getMap("offset");
42 | if (offsetMap.hasKey("x")) {
43 | offsetX = UiUtils.pxToDp(resources, offsetMap.getDouble("x"));
44 | }
45 | if (offsetMap.hasKey("y")) {
46 | offsetY = UiUtils.pxToDp(resources, offsetMap.getDouble("y"));
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/HighlighterViewPackage.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.bridge.JavaScriptModule;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.uimanager.ViewManager;
9 |
10 | import java.util.Arrays;
11 | import java.util.Collections;
12 | import java.util.List;
13 |
14 | public class HighlighterViewPackage implements ReactPackage {
15 |
16 | @Override
17 | public List createNativeModules(ReactApplicationContext reactContext) {
18 | return Collections.emptyList();
19 | }
20 |
21 | public List> createJSModules() {
22 | return Collections.emptyList();
23 | }
24 |
25 | @Override
26 | public List createViewManagers(ReactApplicationContext reactContext) {
27 | return Arrays.asList( new HighlighterViewManager() );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/ReactHacks.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import android.support.annotation.Nullable;
5 |
6 | import com.facebook.react.uimanager.NativeViewHierarchyManager;
7 | import com.facebook.react.uimanager.UIBlock;
8 | import com.facebook.react.uimanager.UIManagerModule;
9 | import com.facebook.react.uimanager.UIViewOperationQueue;
10 |
11 | /**
12 | * ¯\_(ツ)_/¯
13 | */
14 | public class ReactHacks {
15 |
16 | /**
17 | * {@link NativeViewHierarchyManager} is used to resolve a native view by RN tag ({@link NativeViewHierarchyManager#resolveView}). The only way of obtaining it is by
18 | * posting {@link UIBlock} which can take a noticeable amount of time to execute.
19 | */
20 | @Nullable
21 | public static NativeViewHierarchyManager getNativeViewHierarchyManager(UIManagerModule uiManager) {
22 | try {
23 | UIViewOperationQueue mOperationsQueue = (UIViewOperationQueue) ReflectionUtils.getDeclaredField(uiManager.getUIImplementation(), "mOperationsQueue");
24 | return (NativeViewHierarchyManager) ReflectionUtils.getDeclaredField(mOperationsQueue, "mNativeViewHierarchyManager");
25 | } catch (Exception e) {
26 | e.printStackTrace();
27 | return null;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/ReflectionUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import android.support.annotation.Nullable;
5 |
6 | import java.lang.reflect.Field;
7 |
8 | class ReflectionUtils {
9 |
10 | @Nullable
11 | static Object getDeclaredField(Object obj, String fieldName) {
12 | try {
13 | Field f = getField(obj.getClass(), fieldName);
14 | if (f == null) {
15 | return null;
16 | }
17 | f.setAccessible(true);
18 | return f.get(obj);
19 | } catch (Exception e) {
20 | e.printStackTrace();
21 | }
22 | return null;
23 | }
24 |
25 | private static Field getField(Class clazz, String name) {
26 | try {
27 | return clazz.getDeclaredField(name);
28 | } catch (NoSuchFieldException nsfe) {
29 | return getField(clazz.getSuperclass(), name);
30 | } catch (Exception e) {
31 | return null;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/highlighterview/UiUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.highlighterview;
3 |
4 | import android.content.res.Resources;
5 | import android.graphics.Point;
6 | import android.graphics.Rect;
7 | import android.view.Display;
8 | import android.view.View;
9 | import android.view.Window;
10 |
11 | import com.facebook.react.uimanager.ThemedReactContext;
12 |
13 | import java.lang.reflect.Method;
14 |
15 | public class UiUtils {
16 | public static float pxToDp(Resources resources, double pixels) {
17 | return (float) (resources.getDisplayMetrics().density * pixels);
18 | }
19 |
20 | public static int getStatusBarHeight(View view, Window window) {
21 | int height = 0;
22 | if (UiUtils.hasOnScreenSystemBar(window)) {
23 | Resources resources = view.getResources();
24 | int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
25 | if (resourceId > 0) {
26 | height = resources.getDimensionPixelSize(resourceId);
27 | }
28 | }
29 | return height;
30 | }
31 |
32 | public static Rect getVisibleRect(View view) {
33 | Rect myViewRect = new Rect();
34 | view.getGlobalVisibleRect(myViewRect);
35 | return myViewRect;
36 | }
37 |
38 | private static boolean hasOnScreenSystemBar(Window window) {
39 | Display display = window.getWindowManager().getDefaultDisplay();
40 | int rawDisplayHeight = 0;
41 | try {
42 | Method getRawHeight = Display.class.getMethod("getRawHeight");
43 | rawDisplayHeight = (Integer) getRawHeight.invoke(display);
44 | } catch (Exception ex) {
45 | }
46 |
47 | Point point = new Point();
48 | display.getSize(point);
49 | return (rawDisplayHeight - point.y) <= 0;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/textinput/DefaultKeyListener.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.textinput;
3 |
4 | import android.text.Editable;
5 | import android.text.InputType;
6 | import android.text.method.KeyListener;
7 | import android.view.KeyEvent;
8 | import android.view.View;
9 |
10 | class DefaultKeyListener implements KeyListener {
11 | @Override
12 | public int getInputType() {
13 | return InputType.TYPE_NULL;
14 | }
15 |
16 | @Override
17 | public boolean onKeyDown(View view, Editable text, int keyCode, KeyEvent event) {
18 | return false;
19 | }
20 |
21 | @Override
22 | public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
23 | return false;
24 | }
25 |
26 | @Override
27 | public boolean onKeyOther(View view, Editable text, KeyEvent event) {
28 | return false;
29 | }
30 |
31 | @Override
32 | public void clearMetaKeyState(View view, Editable content, int states) {
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/textinput/KeyListenerProxy.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.textinput;
3 |
4 | import android.text.Editable;
5 | import android.text.method.KeyListener;
6 | import android.view.KeyEvent;
7 | import android.view.View;
8 |
9 | import com.facebook.react.bridge.Arguments;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.modules.core.DeviceEventManagerModule;
12 |
13 | public class KeyListenerProxy implements KeyListener {
14 |
15 | final private ReactApplicationContext mContext;
16 | final private KeyListener mKeyListener;
17 |
18 | KeyListenerProxy(ReactApplicationContext context, KeyListener keyListener) {
19 | mContext = context;
20 | mKeyListener = keyListener == null ? new DefaultKeyListener() : keyListener;
21 | }
22 |
23 | @Override
24 | public int getInputType() {
25 | return mKeyListener.getInputType();
26 | }
27 |
28 | @Override
29 | public boolean onKeyDown(View view, Editable text, int keyCode, KeyEvent event) {
30 | return mKeyListener.onKeyDown(view, text, keyCode, event);
31 | }
32 |
33 | @Override
34 | public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
35 | if (keyCode == KeyEvent.KEYCODE_DEL) {
36 | emitBackspacePressEvent();
37 | }
38 | return mKeyListener.onKeyUp(view, text, keyCode, event);
39 | }
40 |
41 | @Override
42 | public boolean onKeyOther(View view, Editable text, KeyEvent event) {
43 | return mKeyListener.onKeyOther(view, text, event);
44 | }
45 |
46 | @Override
47 | public void clearMetaKeyState(View view, Editable content, int states) {
48 | mKeyListener.clearMetaKeyState(view, content, states);
49 | }
50 |
51 | private void emitBackspacePressEvent() {
52 | mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onBackspacePress", Arguments.createMap());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/textinput/TextInputDelKeyHandlerModule.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.textinput;
3 |
4 | import android.util.Log;
5 | import android.view.View;
6 |
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
9 | import com.facebook.react.bridge.ReactMethod;
10 | import com.facebook.react.uimanager.IllegalViewOperationException;
11 | import com.facebook.react.uimanager.NativeViewHierarchyManager;
12 | import com.facebook.react.uimanager.UIBlock;
13 | import com.facebook.react.uimanager.UIManagerModule;
14 | import com.facebook.react.views.textinput.ReactEditText;
15 |
16 | public class TextInputDelKeyHandlerModule extends ReactContextBaseJavaModule {
17 |
18 | private final static String REACT_CLASS = "TextInputDelKeyHandler";
19 |
20 | TextInputDelKeyHandlerModule(ReactApplicationContext reactContext) {
21 | super(reactContext);
22 | }
23 |
24 | @Override
25 | public String getName() {
26 | return REACT_CLASS;
27 | }
28 |
29 | @ReactMethod
30 | public void register(final Integer textInputTag) {
31 | final ReactApplicationContext reactContext = this.getReactApplicationContext();
32 | final UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
33 |
34 | uiManager.addUIBlock(new UIBlock() {
35 | public void execute(NativeViewHierarchyManager viewHierarchyManager) {
36 | Log.d("ReactNativeJS","registering tag = " + textInputTag);
37 | final View view;
38 | try {
39 | view = viewHierarchyManager.resolveView(textInputTag);
40 | } catch (IllegalViewOperationException e) {
41 | Log.d("ReactNativeJS","no view for tag = " + textInputTag);
42 | e.printStackTrace();
43 | return;
44 | }
45 | final ReactEditText editText = ViewUtils.getEditTextInView(view);
46 |
47 | if (editText != null) {
48 | Log.d("ReactNativeJS","has editText for tag = " + textInputTag);
49 | final KeyListenerProxy keyListenerProxy = new KeyListenerProxy(reactContext, editText.getKeyListener());
50 | editText.setKeyListener(keyListenerProxy);
51 | }
52 | }
53 | });
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/textinput/TextInputDelKeyHandlerPackage.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.textinput;
3 |
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.bridge.JavaScriptModule;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.uimanager.ViewManager;
9 |
10 | import java.util.Arrays;
11 | import java.util.Collections;
12 | import java.util.List;
13 |
14 | public class TextInputDelKeyHandlerPackage implements ReactPackage {
15 | @Override
16 | public List createNativeModules(ReactApplicationContext reactContext) {
17 | return Arrays.asList(new TextInputDelKeyHandlerModule(reactContext));
18 | }
19 |
20 | // @Override
21 | // public List> createJSModules() {
22 | // return Collections.emptyList();
23 | // }
24 |
25 | @Override
26 | public List createViewManagers(ReactApplicationContext reactContext) {
27 | return Collections.emptyList();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/textinput/ViewUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.textinput;
3 |
4 | import android.support.annotation.Nullable;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.facebook.react.views.textinput.ReactEditText;
9 |
10 | class ViewUtils {
11 |
12 | @Nullable
13 | static ReactEditText getEditTextInView(View view) {
14 | if (view == null) {
15 | return null;
16 | }
17 |
18 | if (view instanceof ReactEditText) {
19 | return (ReactEditText) view;
20 | }
21 |
22 | if (view instanceof ViewGroup) {
23 | final ViewGroup viewGroup = (ViewGroup) view;
24 |
25 | for (int i = 0; i < viewGroup.getChildCount(); i++) {
26 | final View child = viewGroup.getChildAt(i);
27 | final View childView = getEditTextInView(child);
28 |
29 | if (childView != null) {
30 | return (ReactEditText) childView;
31 | }
32 | }
33 | }
34 | return null;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/wheelpicker/WheelPicker.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.wheelpicker;
3 |
4 | import android.content.Context;
5 | import android.view.ContextThemeWrapper;
6 | import android.widget.LinearLayout;
7 | import android.widget.NumberPicker;
8 |
9 | import com.facebook.react.bridge.Arguments;
10 | import com.facebook.react.bridge.ReactContext;
11 | import com.facebook.react.bridge.WritableMap;
12 | import com.facebook.react.uimanager.events.RCTEventEmitter;
13 | import com.kajoo.reactnativecommon.R;
14 |
15 | import static android.view.View.inflate;
16 |
17 | public class WheelPicker extends NumberPicker{
18 | private Context context;
19 |
20 | public WheelPicker(final Context context) {
21 | super(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle));
22 | this.context = context;
23 | this.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
24 | this.setOnValueChangedListener(new OnValueChangeListener() {
25 | @Override
26 | public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
27 | WritableMap event = Arguments.createMap();
28 | event.putInt("itemIndex", newVal);
29 | ReactContext reactContext = (ReactContext) context;
30 | reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
31 | getId(),
32 | "topChange",
33 | event);
34 | }
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/wheelpicker/WheelPickerManager.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.wheelpicker;
3 |
4 | import android.widget.NumberPicker;
5 |
6 | import com.facebook.react.bridge.ReadableArray;
7 | import com.facebook.react.common.MapBuilder;
8 | import com.facebook.react.uimanager.SimpleViewManager;
9 | import com.facebook.react.uimanager.ThemedReactContext;
10 | import com.facebook.react.uimanager.annotations.ReactProp;
11 | import com.kajoo.reactnativecommon.R;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | import javax.annotation.Nullable;
18 |
19 | public class WheelPickerManager extends SimpleViewManager {
20 | public static final String REACT_CLASS = "WheelPicker";
21 |
22 | @Override
23 | public String getName() {
24 | return REACT_CLASS;
25 | }
26 |
27 | @Override
28 | public WheelPicker createViewInstance(ThemedReactContext context) {
29 | return new WheelPicker(context); //If your customview has more constructor parameters pass it from here.
30 | }
31 |
32 | @ReactProp(name = "data")
33 | public void setData(WheelPicker wheelPicker, @Nullable ReadableArray data) {
34 | NumberPicker numberPicker = (NumberPicker) wheelPicker;
35 | ArrayList dataList = data.toArrayList();
36 | final String[] arrayString= (String[]) dataList.toArray(new String[0]);
37 | numberPicker.setMinValue(0);
38 | numberPicker.setMaxValue(arrayString.length-1);
39 | numberPicker.setDisplayedValues( arrayString );
40 | }
41 |
42 | public Map getExportedCustomBubblingEventTypeConstants() {
43 | return MapBuilder.builder()
44 | .put(
45 | "topChange",
46 | MapBuilder.of(
47 | "phasedRegistrationNames",
48 | MapBuilder.of("bubbled", "onChange")))
49 | .build();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/src/main/java/com/kajoo/reactnativecommon/wheelpicker/WheelPickerPackage.java:
--------------------------------------------------------------------------------
1 |
2 | package com.kajoo.reactnativecommon.wheelpicker;
3 |
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.bridge.JavaScriptModule;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.uimanager.ViewManager;
9 | import com.kajoo.reactnativecommon.wheelpicker.WheelPickerManager;
10 |
11 | import java.util.Arrays;
12 | import java.util.Collections;
13 | import java.util.List;
14 |
15 | public class WheelPickerPackage implements ReactPackage {
16 |
17 | @Override
18 | public List createNativeModules(ReactApplicationContext reactContext) {
19 | return Collections.emptyList();
20 | }
21 |
22 | public List> createJSModules() {
23 | return Collections.emptyList();
24 | }
25 |
26 | @Override
27 | public List createViewManagers(ReactApplicationContext reactContext) {
28 | return Arrays.asList( new WheelPickerManager() );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/android/src/main/res/layout/wheel_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #459FED
7 | #FF4081
8 | #20303c
9 |
10 |
--------------------------------------------------------------------------------
/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/default_installation.md:
--------------------------------------------------------------------------------
1 | # Default Installation instructions
2 |
3 | If your project is a standard React Native project created using `react-native init` (it should have an ios/android directory), then follow these installation instructions:
4 |
5 | ## Step 1: Install react-native-vector-icons
6 |
7 | If you already have this installed, or are using create-react-native-app, this isn't necessary.
8 |
9 | `npm i react-native-vector-icons --save && react-native link react-native-vector-icons`
10 |
11 | *If you have any issues with icons not working or installation of React Native Vector Icons, check out their installation guide [here](https://github.com/oblador/react-native-vector-icons#installation)*
12 |
13 | ## Step 2: Install react-native-common
14 |
15 | ```
16 | yarn add react-native-common
17 | ```
18 |
19 | or
20 |
21 | ```
22 | npm i react-native-common --save
23 | ```
24 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 |
16 | ; Ignore polyfills
17 | .*/Libraries/polyfills/.*
18 |
19 | ; Ignore metro
20 | .*/node_modules/metro/.*
21 |
22 | [include]
23 |
24 | [libs]
25 | node_modules/react-native/Libraries/react-native/react-native-interface.js
26 | node_modules/react-native/flow/
27 |
28 | [options]
29 | emoji=true
30 |
31 | esproposal.optional_chaining=enable
32 | esproposal.nullish_coalescing=enable
33 |
34 | module.system=haste
35 | module.system.haste.use_name_reducers=true
36 | # get basename
37 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
38 | # strip .js or .js.flow suffix
39 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
40 | # strip .ios suffix
41 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
42 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
43 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
44 | module.system.haste.paths.blacklist=.*/__tests__/.*
45 | module.system.haste.paths.blacklist=.*/__mocks__/.*
46 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.*
47 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.*
48 |
49 | munge_underscores=true
50 |
51 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
52 |
53 | module.file_ext=.js
54 | module.file_ext=.jsx
55 | module.file_ext=.json
56 | module.file_ext=.native.js
57 |
58 | suppress_type=$FlowIssue
59 | suppress_type=$FlowFixMe
60 | suppress_type=$FlowFixMeProps
61 | suppress_type=$FlowFixMeState
62 |
63 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
64 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
65 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
66 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
67 |
68 | [version]
69 | ^0.92.0
70 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | * @flow
7 | */
8 |
9 | import React, { Component } from 'react';
10 | import { Platform, StyleSheet, Text, View } from 'react-native';
11 |
12 | const instructions = Platform.select({
13 | ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
14 | android:
15 | 'Double tap R on your keyboard to reload,\n' +
16 | 'Shake or press menu button for dev menu',
17 | });
18 |
19 | type Props = {};
20 | export default class App extends Component {
21 | render() {
22 | return (
23 |
24 | Welcome to React Native!
25 | To get started, edit App.js
26 | {instructions}
27 |
28 | );
29 | }
30 | }
31 |
32 | const styles = StyleSheet.create({
33 | container: {
34 | flex: 1,
35 | justifyContent: 'center',
36 | alignItems: 'center',
37 | backgroundColor: '#F5FCFF',
38 | },
39 | welcome: {
40 | fontSize: 20,
41 | textAlign: 'center',
42 | margin: 10,
43 | },
44 | instructions: {
45 | textAlign: 'center',
46 | color: '#333333',
47 | marginBottom: 5,
48 | },
49 | });
50 |
--------------------------------------------------------------------------------
/example/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.example",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.example",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/example/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.ReactRootView;
6 | import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
7 |
8 | public class MainActivity extends ReactActivity {
9 |
10 | /**
11 | * Returns the name of the main component registered from JavaScript.
12 | * This is used to schedule rendering of the component.
13 | */
14 | @Override
15 | protected String getMainComponentName() {
16 | return "example";
17 | }
18 |
19 | @Override
20 | protected ReactActivityDelegate createReactActivityDelegate() {
21 | return new ReactActivityDelegate(this, getMainComponentName()) {
22 | @Override
23 | protected ReactRootView createRootView() {
24 | return new RNGestureHandlerEnabledRootView(MainActivity.this);
25 | }
26 | };
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.shell.MainReactPackage;
10 | import com.facebook.soloader.SoLoader;
11 |
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | public class MainApplication extends Application implements ReactApplication {
16 |
17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
18 | @Override
19 | public boolean getUseDeveloperSupport() {
20 | return BuildConfig.DEBUG;
21 | }
22 |
23 | @Override
24 | protected List getPackages() {
25 | return Arrays.asList(
26 | new MainReactPackage(),
27 | new RNGestureHandlerPackage()
28 | );
29 | }
30 |
31 | @Override
32 | protected String getJSMainModuleName() {
33 | return "index";
34 | }
35 | };
36 |
37 | @Override
38 | public ReactNativeHost getReactNativeHost() {
39 | return mReactNativeHost;
40 | }
41 |
42 | @Override
43 | public void onCreate() {
44 | super.onCreate();
45 | SoLoader.init(this, /* native exopackage */ false);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | example
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = "28.0.3"
6 | minSdkVersion = 16
7 | compileSdkVersion = 28
8 | targetSdkVersion = 28
9 | supportLibVersion = "28.0.0"
10 | }
11 | repositories {
12 | google()
13 | jcenter()
14 | }
15 | dependencies {
16 | classpath 'com.android.tools.build:gradle:3.3.1'
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | mavenLocal()
26 | google()
27 | jcenter()
28 | maven {
29 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
30 | url "$rootDir/../node_modules/react-native/android"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
6 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'example'
2 | include ':react-native-gesture-handler'
3 | project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
4 |
5 | include ':app'
6 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "displayName": "example"
4 | }
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import { AppRegistry } from 'react-native';
6 | import App from './App';
7 | import { name as appName } from './app.json';
8 |
9 | AppRegistry.registerComponent(appName, () => App);
10 |
--------------------------------------------------------------------------------
/example/ios/example-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/ios/example-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (nonatomic, strong) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import "AppDelegate.h"
9 |
10 | #import
11 | #import
12 | #import
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
19 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
20 | moduleName:@"example"
21 | initialProperties:nil];
22 |
23 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
24 |
25 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
26 | UIViewController *rootViewController = [UIViewController new];
27 | rootViewController.view = rootView;
28 | self.window.rootViewController = rootViewController;
29 | [self.window makeKeyAndVisible];
30 | return YES;
31 | }
32 |
33 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
34 | {
35 | #if DEBUG
36 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
37 | #else
38 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
39 | #endif
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/example/ios/example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/ios/example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSLocationWhenInUseUsageDescription
28 |
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UIViewControllerBasedStatusBarAppearance
42 |
43 | NSLocationWhenInUseUsageDescription
44 |
45 | NSAppTransportSecurity
46 |
47 |
48 | NSAllowsArbitraryLoads
49 |
50 | NSExceptionDomains
51 |
52 | localhost
53 |
54 | NSExceptionAllowsInsecureHTTPLoads
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/example/ios/example/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 |
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/exampleTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | #import
12 | #import
13 |
14 | #define TIMEOUT_SECONDS 600
15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
16 |
17 | @interface exampleTests : XCTestCase
18 |
19 | @end
20 |
21 | @implementation exampleTests
22 |
23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24 | {
25 | if (test(view)) {
26 | return YES;
27 | }
28 | for (UIView *subview in [view subviews]) {
29 | if ([self findSubviewInView:subview matching:test]) {
30 | return YES;
31 | }
32 | }
33 | return NO;
34 | }
35 |
36 | - (void)testRendersWelcomeScreen
37 | {
38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40 | BOOL foundElement = NO;
41 |
42 | __block NSString *redboxError = nil;
43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
44 | if (level >= RCTLogLevelError) {
45 | redboxError = message;
46 | }
47 | });
48 |
49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
52 |
53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
55 | return YES;
56 | }
57 | return NO;
58 | }];
59 | }
60 |
61 | RCTSetLogFunction(RCTDefaultLogFunction);
62 |
63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
65 | }
66 |
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: false,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "react": "16.8.3",
11 | "react-native": "0.59.3",
12 | "react-native-common": "link:..",
13 | "react-native-gesture-handler": "^1.1.0",
14 | "react-navigation": "^3.6.0"
15 | },
16 | "devDependencies": {
17 | "@babel/core": "^7.4.0",
18 | "@babel/runtime": "^7.4.2",
19 | "babel-jest": "^24.5.0",
20 | "jest": "^24.5.0",
21 | "metro-react-native-babel-preset": "^0.53.1",
22 | "react-test-renderer": "16.8.3"
23 | },
24 | "jest": {
25 | "preset": "react-native"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/highlighterview/HighlighterView.h:
--------------------------------------------------------------------------------
1 | //
2 | // HighlighterView.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 2/17/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #ifndef HighlighterView_h
13 | #define HighlighterView_h
14 |
15 | @interface HighlighterView : UIView
16 |
17 | - (id)initWithFrame:(CGRect)frame bridge:(RCTBridge*)bridge;
18 |
19 | @property (nonatomic) CGRect highlightFrame;
20 | @property (nonatomic, strong) NSNumber *borderRadius;
21 | @property (nonatomic, strong) UIColor *overlayColor;
22 | @property (nonatomic, strong) UIColor *strokeColor;
23 | @property (nonatomic, strong) NSNumber *strokeWidth;
24 | @property (nonatomic, strong) NSNumber *highlightViewTag;
25 | @property (nonatomic, strong) NSDictionary *highlightViewTagParams;
26 |
27 | @end
28 |
29 | #endif /* HighlighterView_h */
30 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/highlighterview/HighlighterViewManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // HighlighterViewManager.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 2/17/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #ifndef HighlighterViewManager_h
13 | #define HighlighterViewManager_h
14 |
15 | @interface HighlighterViewManager : RCTViewManager
16 |
17 | @end
18 |
19 | #endif /* HighlighterViewManager_h */
20 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/highlighterview/HighlighterViewManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // HighlighterViewManager.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 2/17/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "HighlighterViewManager.h"
10 | #import "HighlighterView.h"
11 |
12 | @implementation HighlighterViewManager
13 |
14 | RCT_EXPORT_MODULE()
15 |
16 | - (dispatch_queue_t)methodQueue {
17 | return dispatch_get_main_queue();
18 | }
19 |
20 | - (UIView *)view
21 | {
22 | return [[HighlighterView alloc] initWithFrame:CGRectZero bridge:self.bridge];
23 | }
24 |
25 | RCT_REMAP_VIEW_PROPERTY(highlightFrame, highlightFrame, CGRect)
26 | RCT_REMAP_VIEW_PROPERTY(highlightViewTag, highlightViewTag, NSNumber)
27 | RCT_REMAP_VIEW_PROPERTY(highlightViewTagParams, highlightViewTagParams, NSDictionary)
28 | RCT_REMAP_VIEW_PROPERTY(overlayColor, overlayColor, UIColor)
29 | RCT_REMAP_VIEW_PROPERTY(borderRadius, borderRadius, NSNumber)
30 | RCT_REMAP_VIEW_PROPERTY(strokeColor, strokeColor, UIColor)
31 | RCT_REMAP_VIEW_PROPERTY(strokeWidth, strokeWidth, NSNumber)
32 |
33 | @end
34 |
35 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaManager.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #ifndef SafeAreaManager_h
13 | #define SafeAreaManager_h
14 |
15 | @interface SafeAreaManager : RCTEventEmitter
16 |
17 | @end
18 |
19 | #endif /* SafeAreaManager_h */
20 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaManager.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "SafeAreaManager.h"
10 | #import
11 | #import
12 |
13 | static NSString *const UIWindowSafeAreaInsetsDidChangeNotification = @"SafeAreaManager.UIWindowSafeAreaInsetsDidChangeNotification";
14 | static NSString *const SafeAreaInsetsDidChangeEvent = @"SafeAreaInsetsDidChangeEvent";
15 | static id (*_swz_safeAreaInsetsDidChange_orig)(id self, SEL _cmd);
16 |
17 | @interface SafeAreaManager () {
18 | UIEdgeInsets _cachedSafeAreaInsets;
19 | }
20 | @end
21 |
22 | @implementation SafeAreaManager
23 |
24 | RCT_EXPORT_MODULE()
25 |
26 | - (dispatch_queue_t)methodQueue {
27 | return dispatch_get_main_queue();
28 | }
29 |
30 | - (NSArray *)supportedEvents {
31 | return @[SafeAreaInsetsDidChangeEvent];
32 | }
33 |
34 | - (instancetype)init {
35 | self = [super init];
36 | if (self) {
37 | _cachedSafeAreaInsets = [self getCurrentSafeAreaInsets];
38 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowSafeAreaDidChange) name:UIWindowSafeAreaInsetsDidChangeNotification object:nil];
39 | [self applySizzles];
40 | }
41 | return self;
42 | }
43 |
44 | -(void)dealloc {
45 | [[NSNotificationCenter defaultCenter] removeObserver:self];
46 | }
47 |
48 | - (void)windowSafeAreaDidChange {
49 | UIEdgeInsets currentSafeAreaInsets = [self getCurrentSafeAreaInsets];
50 | if (!UIEdgeInsetsEqualToEdgeInsets(currentSafeAreaInsets, _cachedSafeAreaInsets)) {
51 | _cachedSafeAreaInsets = currentSafeAreaInsets;
52 |
53 | NSUInteger listenerCount = [[self valueForKey:@"_listenerCount"] unsignedIntegerValue];
54 | if (listenerCount > 0) {
55 | [self sendEventWithName:SafeAreaInsetsDidChangeEvent body:[self getResultDicFromSafeArea:_cachedSafeAreaInsets]];
56 | }
57 | }
58 | }
59 |
60 | -(UIEdgeInsets)getCurrentSafeAreaInsets {
61 | UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
62 | #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3
63 | if (@available(iOS 11.0, *)) {
64 | safeAreaInsets = [UIApplication sharedApplication].keyWindow.safeAreaInsets;
65 | }
66 | #endif
67 | return safeAreaInsets;
68 | }
69 |
70 | #pragma mark - swizzles
71 |
72 | - (void)applySizzles {
73 | #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3
74 | if (@available(iOS 11.0, *)) {
75 | static dispatch_once_t onceToken;
76 | dispatch_once(&onceToken, ^{
77 | Method originalMethod = class_getInstanceMethod([UIWindow class], @selector(safeAreaInsetsDidChange));
78 | Method replacementMethod = class_getInstanceMethod([SafeAreaManager class], @selector(_swz_safeAreaInsetsDidChange));
79 | _swz_safeAreaInsetsDidChange_orig = (void*)method_getImplementation(originalMethod);
80 | method_exchangeImplementations(originalMethod, replacementMethod);
81 | });
82 | }
83 | #endif
84 | }
85 |
86 | - (void)_swz_safeAreaInsetsDidChange {
87 | // _swz_safeAreaInsetsDidChange_orig(self, _cmd);
88 | [[NSNotificationCenter defaultCenter] postNotificationName:UIWindowSafeAreaInsetsDidChangeNotification object:nil];
89 | }
90 |
91 | #pragma mark - helper methods
92 |
93 | - (NSDictionary*)getResultDicFromSafeArea:(UIEdgeInsets)safeAreaInsets {
94 | return @{@"top": @(safeAreaInsets.top),
95 | @"left": @(safeAreaInsets.left),
96 | @"bottom": @(safeAreaInsets.bottom),
97 | @"right": @(safeAreaInsets.right)
98 | };
99 | }
100 |
101 | #pragma mark - public API
102 |
103 | RCT_EXPORT_METHOD(getSafeAreaInsets:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
104 | UIEdgeInsets safeAreaInsets = [self getCurrentSafeAreaInsets];
105 | resolve([self getResultDicFromSafeArea:safeAreaInsets]);
106 | }
107 |
108 | @end
109 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerShadowView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerShadowView.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #ifndef SafeAreaSpacerShadowView_h
12 | #define SafeAreaSpacerShadowView_h
13 |
14 | @interface SafeAreaSpacerShadowView : RCTShadowView
15 |
16 | @end
17 |
18 | #endif /* SafeAreaSpacerShadowView_h */
19 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerShadowView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerShadowView.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "SafeAreaSpacerShadowView.h"
10 | #import "SafeAreaSpacerViewLocalData.h"
11 |
12 | @implementation SafeAreaSpacerShadowView
13 |
14 | - (void)setLocalData:(SafeAreaSpacerViewLocalData *)localData
15 | {
16 | UIEdgeInsets insets = localData.insets;
17 |
18 | super.height = (YGValue){insets.bottom + insets.top, YGUnitPoint};
19 | [self didSetProps:@[@"height"]];
20 | }
21 |
22 | /**
23 | * Removing support for setting height from any outside code
24 | * to prevent interferring this with local data.
25 | */
26 | - (void)setHeight:(YGValue)height {}
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerView.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #ifndef SafeAreaSpacerView_h
12 | #define SafeAreaSpacerView_h
13 |
14 | @class RCTBridge;
15 |
16 | @interface SafeAreaSpacerView : RCTView
17 | - (instancetype)initWithBridge:(RCTBridge *)bridge;
18 | @end
19 |
20 | #endif /* SafeAreaSpacerView_h */
21 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerView.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "SafeAreaSpacerView.h"
10 | #import "SafeAreaSpacerViewLocalData.h"
11 | #import
12 | #import
13 |
14 | @implementation SafeAreaSpacerView
15 | {
16 | __weak RCTBridge *_bridge;
17 | UIEdgeInsets _currentSafeAreaInsets;
18 | //these flags are used to prevent an endless cycle of safe area insets update. setting the view height changes it's frame, and in some cases `reactSetFrame` causes more and more updates with varying sizes
19 | BOOL _ignoreNextInsetUpdate;
20 | BOOL _insetsWereUpdated;
21 | }
22 |
23 | - (instancetype)initWithBridge:(RCTBridge *)bridge
24 | {
25 | if (self = [super initWithFrame:CGRectZero])
26 | {
27 | _bridge = bridge;
28 | _ignoreNextInsetUpdate = NO;
29 | _insetsWereUpdated = NO;
30 | }
31 | return self;
32 | }
33 |
34 | - (void)reactSetFrame:(CGRect)frame
35 | {
36 | if (self.window != nil && _insetsWereUpdated)
37 | {
38 | _ignoreNextInsetUpdate = YES;
39 | dispatch_async(dispatch_get_main_queue(), ^{
40 | _ignoreNextInsetUpdate = NO;
41 | });
42 | }
43 |
44 | [super reactSetFrame:frame];
45 | }
46 |
47 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
48 |
49 | static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold)
50 | {
51 | return
52 | ABS(insets1.left - insets2.left) <= threshold &&
53 | ABS(insets1.right - insets2.right) <= threshold &&
54 | ABS(insets1.top - insets2.top) <= threshold &&
55 | ABS(insets1.bottom - insets2.bottom) <= threshold;
56 | }
57 |
58 | - (void)safeAreaInsetsDidChange
59 | {
60 | if (![self respondsToSelector:@selector(safeAreaInsets)] || _ignoreNextInsetUpdate)
61 | {
62 | _ignoreNextInsetUpdate = NO;
63 | _insetsWereUpdated = NO;
64 | return;
65 | }
66 |
67 | UIEdgeInsets safeAreaInsets = self.safeAreaInsets;
68 |
69 | if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()))
70 | {
71 | return;
72 | }
73 |
74 | _currentSafeAreaInsets = safeAreaInsets;
75 | _insetsWereUpdated = YES;
76 |
77 | SafeAreaSpacerViewLocalData *localData = [[SafeAreaSpacerViewLocalData alloc] initWithInsets:safeAreaInsets];
78 | [_bridge.uiManager setLocalData:localData forView:self];
79 | }
80 |
81 | #endif
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerViewLocalData.h:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerViewLocalData.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #ifndef SafeAreaSpacerViewLocalData_h
12 | #define SafeAreaSpacerViewLocalData_h
13 |
14 | @interface SafeAreaSpacerViewLocalData : NSObject
15 |
16 | - (instancetype)initWithInsets:(UIEdgeInsets)insets;
17 |
18 | @property (atomic, readonly) UIEdgeInsets insets;
19 |
20 | @end
21 |
22 | #endif /* SafeAreaSpacerViewLocalData_h */
23 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerViewLocalData.m:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerViewLocalData.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "SafeAreaSpacerViewLocalData.h"
10 |
11 | @implementation SafeAreaSpacerViewLocalData
12 |
13 | - (instancetype)initWithInsets:(UIEdgeInsets)insets
14 | {
15 | if (self = [super init]) {
16 | _insets = insets;
17 | }
18 |
19 | return self;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerViewManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerViewManager.h
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #ifndef SafeAreaSpacerViewManager_h
12 | #define SafeAreaSpacerViewManager_h
13 |
14 | @interface SafeAreaSpacerViewManager : RCTViewManager
15 |
16 | @end
17 |
18 | #endif /* SafeAreaSpacerViewManager_h */
19 |
--------------------------------------------------------------------------------
/ios/reactnativecommon/safearea/SafeAreaSpacerViewManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // SafeAreaSpacerViewManager.m
3 | // RNCommon
4 | //
5 | // Created by Reza on 3/19/18.
6 | // Copyright © 2018 kajoo. All rights reserved.
7 | //
8 |
9 | #import "SafeAreaSpacerViewManager.h"
10 |
11 | #import "SafeAreaSpacerShadowView.h"
12 | #import "SafeAreaSpacerView.h"
13 | #import
14 |
15 | @implementation SafeAreaSpacerViewManager
16 |
17 | RCT_EXPORT_MODULE()
18 |
19 | - (dispatch_queue_t)methodQueue
20 | {
21 | return dispatch_get_main_queue();
22 | }
23 |
24 | - (UIView *)view
25 | {
26 | return [[SafeAreaSpacerView alloc] initWithBridge:self.bridge];
27 | }
28 |
29 | - (SafeAreaSpacerShadowView *)shadowView
30 | {
31 | return [SafeAreaSpacerShadowView new];
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/jest-setup.js:
--------------------------------------------------------------------------------
1 | const { NativeModules } = require('react-native');
2 |
3 | NativeModules.StatusBarManager = { getHeight: jest.fn() };
4 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true
5 | },
6 | "exclude": [
7 | "node_modules"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-common",
3 | "version": "3.1.1",
4 | "description": "UI Toolset & Components and API Library for React Native with RTL support.",
5 | "main": "src/index.js",
6 | "typings": "typings/index.d.ts",
7 | "scripts": {
8 | "start": "watchman watch-del-all && react-native start",
9 | "ios": "react-native run-ios --simulator='iPhone 8'",
10 | "android": "react-native run-android",
11 | "pretest": "npm run lint",
12 | "lint": "eslint .",
13 | "test": "jest",
14 | "test:watch": "jest --watch",
15 | "test:coverage": "jest --coverage",
16 | "build:ts": "rm -rf dist-ts && ./scripts/build-ts.sh",
17 | "build:typings": "rm -rf ./typings && ./scripts/build-typings.sh && tsc"
18 | },
19 | "files": [
20 | "src/",
21 | "LICENSE",
22 | "README.md"
23 | ],
24 | "keyword": [
25 | "react",
26 | "react-native",
27 | "react-native-common",
28 | "components",
29 | "animation",
30 | "colors",
31 | "extensions",
32 | "forms",
33 | "icons",
34 | "modals",
35 | "images",
36 | "layout",
37 | "rendering",
38 | "styling",
39 | "transformers",
40 | "ios",
41 | "android"
42 | ],
43 | "author": {
44 | "name": "Reza Ghorbani",
45 | "email": "r.ghorbani.f@gmail.com"
46 | },
47 | "license": "MIT",
48 | "bugs": {
49 | "url": "https://github.com/rghorbani/react-native-common/issues"
50 | },
51 | "dependencies": {
52 | "hoist-non-react-statics": "^3.3.0",
53 | "lodash": "^4.17.15",
54 | "prop-types": "^15.7.2",
55 | "react-native-deprecated-custom-components": "^0.1.2",
56 | "react-native-keyboard-aware-scrollview": "^2.0.0",
57 | "react-native-ui-lib": "^3.39.0"
58 | },
59 | "devDependencies": {
60 | "babel-cli": "^6.26.0",
61 | "babel-jest": "^24.9.0",
62 | "babel-preset-react": "^6.24.1",
63 | "babel-preset-react-native": "^4.0.1",
64 | "eslint": "^6.6.0",
65 | "eslint-config-kajoo": "^1.5.0",
66 | "husky": "^3.0.9",
67 | "jest": "^24.9.0",
68 | "lint-staged": "^8.1.5",
69 | "react": "16.6.3",
70 | "react-native": "0.57.8"
71 | },
72 | "peerDependencies": {
73 | "react": "*",
74 | "react-native": "*"
75 | },
76 | "jest": {
77 | "preset": "react-native",
78 | "testPathIgnorePatterns": [
79 | "src/components/navigator",
80 | "/e2e/",
81 | "/node_modules/",
82 | "/typings/"
83 | ],
84 | "setupFiles": [
85 | "./jest-setup.js"
86 | ]
87 | },
88 | "rnpm": {
89 | "android": {
90 | "packageImportPath": "import com.wix.reactnativeuilib.textinput.TextInputDelKeyHandlerPackage;",
91 | "packageInstance": "new TextInputDelKeyHandlerPackage()"
92 | },
93 | "ios": {
94 | "project": "ios/reactnativeuilib.xcodeproj"
95 | }
96 | },
97 | "homepage": "https://github.com/rghorbani/react-native-common",
98 | "contributors": [
99 | {
100 | "name": "rghorbani",
101 | "email": "r.ghorbani.f@gmail.com"
102 | }
103 | ],
104 | "repository": {
105 | "type": "git",
106 | "url": "https://github.com/rghorbani/react-native-common"
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/scripts/build-ts.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # copy all js files to dist-ts, prepare for transformation
3 | # find ./src -iname "*.js" -type f | cut -d/ -f3- | while read b; do mkdir -p "dist-ts/`dirname $b`" && cp src/$b dist-ts/$b ; done
4 | find ./src -type f | cut -d/ -f3- | while read b; do mkdir -p "dist-ts/`dirname $b`" && cp src/$b dist-ts/$b ; done
5 | # transform only js files inside /components/
6 | # find ./dist-ts -iname "*.js" -ipath "*/components/*" -type f | while read file; do react-js-to-ts $file; done
7 | find ./dist-ts -iname "*.js" -type f | while read file; do react-js-to-ts $file; done
8 |
--------------------------------------------------------------------------------
/scripts/build-typings.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # create dist-ts and move all js files to it
3 | # find ./dist-ts -iname "*.js" -type f | cut -d/ -f3- | while read b; do mkdir -p "dist/`dirname $b`" && cp dist-ts/$b dist/$b ; done
4 | find ./dist-ts -iname "*.png" -type f | cut -d/ -f3- | while read b; do mkdir -p "typings/`dirname $b`" && cp dist-ts/$b typings/$b ; done
5 |
--------------------------------------------------------------------------------
/simple.sh:
--------------------------------------------------------------------------------
1 | git add .
2 | git commit -am 'fb'
3 | git push
4 |
--------------------------------------------------------------------------------
/src/assets/icons/check-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check-small.png
--------------------------------------------------------------------------------
/src/assets/icons/check-small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check-small@2x.png
--------------------------------------------------------------------------------
/src/assets/icons/check-small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check-small@3x.png
--------------------------------------------------------------------------------
/src/assets/icons/check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check.png
--------------------------------------------------------------------------------
/src/assets/icons/check@1.5x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check@1.5x.png
--------------------------------------------------------------------------------
/src/assets/icons/check@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check@2x.png
--------------------------------------------------------------------------------
/src/assets/icons/check@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check@3x.png
--------------------------------------------------------------------------------
/src/assets/icons/check@4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/check@4x.png
--------------------------------------------------------------------------------
/src/assets/icons/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const icons = {
10 | check: require('./check.png'),
11 | checkSmall: require('./check-small.png'),
12 | x: require('./x.png'),
13 | search: require('./search.png'),
14 | };
15 |
16 | module.exports = icons;
17 |
--------------------------------------------------------------------------------
/src/assets/icons/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/search.png
--------------------------------------------------------------------------------
/src/assets/icons/search@1.5x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/search@1.5x.png
--------------------------------------------------------------------------------
/src/assets/icons/search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/search@2x.png
--------------------------------------------------------------------------------
/src/assets/icons/search@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/search@3x.png
--------------------------------------------------------------------------------
/src/assets/icons/search@4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/search@4x.png
--------------------------------------------------------------------------------
/src/assets/icons/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/x.png
--------------------------------------------------------------------------------
/src/assets/icons/x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/x@2x.png
--------------------------------------------------------------------------------
/src/assets/icons/x@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/assets/icons/x@3x.png
--------------------------------------------------------------------------------
/src/assets/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 |
11 | const emojis = require('./emojis');
12 | const icons = require('./icons');
13 |
14 | class Assets {
15 | emojis = emojis;
16 | icons = icons;
17 |
18 | loadAssetsGroup(groupName, assets) {
19 | if (!_.isString(groupName)) {
20 | throw new Error('group name should be a string');
21 | }
22 |
23 | if (!_.isPlainObject(assets)) {
24 | throw new Error('assets should be a hash map');
25 | }
26 |
27 | _.forEach(assets, (value, key) => {
28 | _.set(this, `${groupName}.${key}`, value);
29 | });
30 | }
31 | }
32 |
33 | module.exports = new Assets();
34 |
--------------------------------------------------------------------------------
/src/components/Colors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | // const colors = {
10 | // red: 'rgb(255, 59, 48)',
11 | // orange: 'rgb(255, 149, 0)',
12 | // yellow: 'rgb(255, 204, 0)',
13 | // green: 'rgb(76, 217, 100)',
14 | // tealBlue: 'rgb(90, 200, 250)',
15 | // blue: 'rgb(0, 122, 255)',
16 | // purple: 'rgb(88, 86, 214)',
17 | // pink: 'rgb(255, 45, 85)',
18 | // };
19 |
20 | const TRANSACTION_TYPE_COLORS = {
21 | '1': '#3cc26b',
22 | '2': '#fb5959',
23 | };
24 |
25 | function colorForTransactionType(type: ?string): string {
26 | if (!type) {
27 | return '#2196F3';
28 | }
29 |
30 | let color = TRANSACTION_TYPE_COLORS[type.toString()];
31 | if (!color) {
32 | console.warn(`Transaction type '${type}' has no color`);
33 | color = '#2196F3';
34 | }
35 | return color;
36 | }
37 |
38 | function colorForAmount(amount: ?number): string {
39 | if (!amount) {
40 | return '#2196F3';
41 | }
42 |
43 | if (amount < 0) {
44 | return '#fb5959';
45 | } else {
46 | return '#3cc26b';
47 | }
48 | }
49 |
50 | function colorWithHSL(count: number, index: number): string {
51 | const hue = Math.round((360 * index) / (count + 1));
52 | return `hsl(${hue}, 74%, 65%)`;
53 | }
54 |
55 | module.exports = {
56 | primary: '#32b189',
57 | tintColor: '#2db58c',
58 | red: '#fb5959',
59 | green: '#3cc26b',
60 | headerBackground: '#32b189',
61 | actionText: '#3FB4CF',
62 | inactiveText: '#9B9B9B',
63 | darkText: '#032250',
64 | mediumText: '#555555',
65 | lightText: '#7F91A7',
66 | cellBorder: '#EEEEEE',
67 | darkBackground: '#183E63',
68 | inputUnderlineActive: 'green',
69 | inputUnderline: '#9B9B9B',
70 | divider: '#e2e3e5',
71 | colorForTransactionType,
72 | colorForAmount,
73 | colorWithHSL,
74 | };
75 |
--------------------------------------------------------------------------------
/src/components/LoadingView.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const { ActivityIndicator, Text, View, StyleSheet } = require('react-native');
11 |
12 | class LoadingView extends React.Component {
13 | static displayName = 'LoadingView';
14 |
15 | static defaultProps = {
16 | loading: false,
17 | type: 'secondary',
18 | caption: 'در حال دریافت اطلاعات ...',
19 | };
20 |
21 | render() {
22 | if (!this.props.loading) {
23 | return null;
24 | }
25 |
26 | if (this.props.type === 'primary') {
27 | return (
28 |
29 |
30 |
37 | {this.props.caption}
38 |
39 |
40 | );
41 | }
42 |
43 | return (
44 |
45 |
46 |
47 | {this.props.caption}
48 |
49 |
50 | );
51 | }
52 | }
53 |
54 | const styles = StyleSheet.create({
55 | container: {
56 | flex: 1,
57 | backgroundColor: 'transparent',
58 | alignItems: 'center',
59 | justifyContent: 'center',
60 | paddingHorizontal: 10,
61 | },
62 | indicator: {
63 | transform: [{ scale: 1.2 }],
64 | },
65 | primary: {
66 | backgroundColor: 'rgba(0, 0, 0, 0.6)',
67 | position: 'absolute',
68 | top: 0,
69 | bottom: 0,
70 | left: 0,
71 | right: 0,
72 | },
73 | caption: {
74 | marginTop: 10,
75 | fontSize: 15,
76 | color: 'black',
77 | },
78 | primaryTitle: {
79 | color: '#FFFFFF',
80 | },
81 | });
82 |
83 | module.exports = LoadingView;
84 |
--------------------------------------------------------------------------------
/src/components/RGFText.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | import React from 'react';
10 | import ReactNative, { StyleSheet, Dimensions } from 'react-native';
11 | import RGFColors from './RGFColors';
12 |
13 | export function Text({ style, ...props }: Object): ReactElement {
14 | return ;
15 | }
16 |
17 | export function NumText({ style, ...props }: Object): ReactElement {
18 | return ;
19 | }
20 |
21 | export function Heading1({ style, ...props }: Object): ReactElement {
22 | return (
23 |
24 | );
25 | }
26 |
27 | export function Paragraph({ style, ...props }: Object): ReactElement {
28 | return ;
29 | }
30 |
31 | export function numberWithCommas(str) {
32 | if (str === undefined || str === '') {
33 | return '';
34 | }
35 | // TODO: Experiment
36 | // for (var i = 0; i < 10; i++) {
37 | // x = x.replace(convertToPersian[i], i);
38 | // }
39 | let parts = str.toString().split('.');
40 | parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
41 | return parts.join('.');
42 | }
43 |
44 | export function parseNumberWithCommas(str) {
45 | str = str.replace(/,/g, '');
46 | let pattern = /^\d+$/;
47 | if (!pattern.test(str)) {
48 | console.error('Error: parseNumberWithCommas', str);
49 | return '';
50 | }
51 |
52 | str = parseInt(str, 10);
53 | return str;
54 | }
55 |
56 | const scale = Dimensions.get('window').width / 375;
57 |
58 | function normalize(size: number): number {
59 | return Math.round(scale * size);
60 | }
61 |
62 | const styles = StyleSheet.create({
63 | font: {
64 | // fontFamily: require('../env').textFont,
65 | },
66 | numFont: {
67 | // fontFamily: require('../env').digitFont,
68 | },
69 | h1: {
70 | fontSize: normalize(24),
71 | lineHeight: normalize(27),
72 | color: RGFColors.darkText,
73 | fontWeight: 'bold',
74 | letterSpacing: -1,
75 | },
76 | p: {
77 | fontSize: normalize(15),
78 | lineHeight: normalize(23),
79 | color: RGFColors.lightText,
80 | },
81 | });
82 |
--------------------------------------------------------------------------------
/src/components/connection/__test__/index.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const ConnectionStatusBar = require('../index');
11 |
12 | describe('ConnectionStatusBar', () => {
13 | let uut;
14 | beforeEach(() => {
15 | uut = new ConnectionStatusBar({});
16 | ConnectionStatusBar.unregisterGlobalOnConnectionLost();
17 | });
18 |
19 | describe('registerGlobalOnConnectionLost', () => {
20 | it('should register a callback for when connection is lost', () => {
21 | const callback = jest.fn();
22 | expect(ConnectionStatusBar.onConnectionLost).toBe(undefined);
23 | ConnectionStatusBar.registerGlobalOnConnectionLost(callback);
24 | expect(ConnectionStatusBar.onConnectionLost).toBe(callback);
25 | ConnectionStatusBar.unregisterGlobalOnConnectionLost();
26 | expect(ConnectionStatusBar.onConnectionLost).toBe(undefined);
27 | });
28 |
29 | it('should call onConnectionLost callback when connection state changed from connected to disconnected', () => {
30 | const callback = jest.fn();
31 | ConnectionStatusBar.registerGlobalOnConnectionLost(callback);
32 | _.set(uut, 'state.isConnected', true);
33 |
34 | uut.onConnectionChange({ type: 'none' });
35 |
36 | expect(callback).toHaveBeenCalled();
37 | });
38 |
39 | it('should not call onConnectionLost callback when connection state changed from disconnected to connected', () => {
40 | const callback = jest.fn();
41 | ConnectionStatusBar.registerGlobalOnConnectionLost(callback);
42 | _.set(uut, 'state.isConnected', false);
43 |
44 | uut.onConnectionChange({ type: 'wifi' });
45 |
46 | expect(callback).not.toHaveBeenCalled();
47 | });
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/src/components/containers/ListContainer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { Platform, Image, TouchableOpacity, View } = require('react-native');
12 |
13 | const Header = require('./Header');
14 | const StyleSheet = require('./StyleSheet');
15 |
16 | import type { Item as HeaderItem } from 'Header';
17 |
18 | type Props = {
19 | title: string,
20 | leftItem?: HeaderItem,
21 | rightItem?: HeaderItem,
22 | extraItems?: Array,
23 | selectedSectionColor: string,
24 | backgroundImage: number,
25 | backgroundColor: string,
26 | children?: any,
27 | };
28 |
29 | class ListContainer extends React.Component {
30 | props: Props;
31 |
32 | static defaultProps = {
33 | selectedSectionColor: 'white',
34 | };
35 |
36 | static contextTypes = {
37 | openDrawer: PropTypes.func,
38 | hasUnreadNotifications: PropTypes.number,
39 | };
40 |
41 | constructor(props: Props) {
42 | super(props);
43 |
44 | (this: any).handleShowMenu = this.handleShowMenu.bind(this);
45 | (this: any).renderButton = this.renderButton.bind(this);
46 | }
47 |
48 | render() {
49 | let leftItem = this.props.leftItem;
50 | if (!leftItem && Platform.OS === 'android') {
51 | leftItem = {
52 | layout: 'icon',
53 | title: 'Menu',
54 | icon: this.context.hasUnreadNotifications
55 | ? require('./img/hamburger-unread.png')
56 | : require('./img/hamburger.png'),
57 | onPress: this.handleShowMenu,
58 | };
59 | }
60 |
61 | return (
62 |
63 |
64 |
70 |
71 | {this.props.children}
72 | {this.renderButton()}
73 |
74 | );
75 | }
76 |
77 | handleShowMenu() {
78 | this.context.openDrawer();
79 | }
80 |
81 | renderButton() {
82 | if (Platform.OS === 'ios' || this.props.onPress === undefined) {
83 | return null;
84 | }
85 |
86 | return (
87 |
88 |
89 |
90 | );
91 | }
92 | }
93 |
94 | const styles = StyleSheet.create({
95 | container: {
96 | flex: 1,
97 | backgroundColor: 'white',
98 | },
99 | content: {
100 | flex: 1,
101 | },
102 | headerWrapper: {
103 | android: {
104 | elevation: 2,
105 | backgroundColor: 'transparent',
106 | // FIXME: elevation doesn't seem to work without setting border
107 | borderRightWidth: 1,
108 | marginRight: -1,
109 | borderRightColor: 'transparent',
110 | },
111 | },
112 | addButton: {
113 | position: 'absolute',
114 | bottom: 10,
115 | left: 10,
116 | },
117 | });
118 |
119 | module.exports = ListContainer;
120 |
--------------------------------------------------------------------------------
/src/components/containers/PageContainer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { View, ViewPropTypes } = require('react-native');
12 |
13 | const Header = require('../header');
14 | import StyleSheet from '../other/StyleSheet';
15 |
16 | class PageContainer extends React.Component {
17 | static propTypes = {
18 | rtl: PropTypes.bool,
19 | ...Header.propTypes,
20 | headerChildren: PropTypes.any,
21 | children: PropTypes.any,
22 | contentStyle: ViewPropTypes.style,
23 | style: ViewPropTypes.style,
24 | };
25 |
26 | static defaultProps = {
27 | rtl: false,
28 | };
29 |
30 | constructor(props) {
31 | super(props);
32 | }
33 |
34 | render() {
35 | let {
36 | rtl,
37 | leftItems,
38 | rightItems,
39 | children,
40 | headerStyle,
41 | style,
42 | contentStyle,
43 | ...props
44 | } = this.props;
45 |
46 | if (rtl) {
47 | let tmp = leftItems;
48 | leftItems = rightItems;
49 | rightItems = tmp;
50 | }
51 |
52 | return (
53 |
54 |
55 |
62 | {this.props.headerChildren}
63 |
64 |
65 | {children}
66 |
67 | );
68 | }
69 | }
70 |
71 | const styles = StyleSheet.create({
72 | container: {
73 | flex: 1,
74 | backgroundColor: 'white',
75 | },
76 | content: {
77 | flex: 1,
78 | },
79 | headerWrapper: {
80 | android: {
81 | backgroundColor: 'transparent',
82 | },
83 | },
84 | });
85 |
86 | module.exports = PageContainer;
87 |
--------------------------------------------------------------------------------
/src/components/containers/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = {
10 | get PageContainer() {
11 | return require('./PageContainer');
12 | },
13 | // get ListContainer() { return require('./ListContainer'); },
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/header/ItemWrapper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { Dimensions, Image, TouchableOpacity } = require('react-native');
12 | const { BaseComponent, Text, View } = require('react-native-ui-lib');
13 |
14 | import StyleSheet from '../other/StyleSheet';
15 |
16 | const SCREEN_WIDTH = Dimensions.get('window').width;
17 | const IOS_ITEM_TEXT_SIZE = SCREEN_WIDTH < 375 ? 10 : 13;
18 |
19 | class ItemWrapper extends BaseComponent {
20 | static displayName = 'Header.ItemWrapper';
21 |
22 | static propTypes = {
23 | /**
24 | * item object
25 | */
26 | item: PropTypes.shape({
27 | title: PropTypes.string,
28 | icon: PropTypes.oneOfType([
29 | PropTypes.element,
30 | PropTypes.string,
31 | PropTypes.number,
32 | ]),
33 | iconSource: PropTypes.any,
34 | layout: PropTypes.oneOf(['default', 'both', 'icon', 'title']),
35 | onPress: PropTypes.func,
36 | style: PropTypes.oneOfType([
37 | PropTypes.object,
38 | PropTypes.number,
39 | PropTypes.array,
40 | ]),
41 | }),
42 | /**
43 | * item color
44 | */
45 | color: PropTypes.string,
46 | /**
47 | * item size
48 | */
49 | size: PropTypes.number,
50 | };
51 |
52 | static defaultProps = {
53 | size: 30,
54 | };
55 |
56 | generateStyles() {
57 | this.styles = createStyles(this.props);
58 | }
59 |
60 | render() {
61 | const { item, color, size } = this.props;
62 | if (!item) {
63 | return null;
64 | }
65 |
66 | let content;
67 | const { title, icon, iconSource, layout, onPress, style } = item;
68 |
69 | if (layout !== 'icon' && title) {
70 | content = (
71 |
72 | {title.toUpperCase()}
73 |
74 | );
75 | } else if (layout === 'both' && title && icon) {
76 | if (React.isValidElement(icon)) {
77 | content = icon;
78 | } else if (typeof icon === 'string') {
79 | const Icon = iconSource;
80 | content = ;
81 | } else {
82 | content = ;
83 | }
84 | content = (
85 |
86 | {content}
87 |
91 | {title.toUpperCase()}
92 |
93 |
94 | );
95 | } else if (icon) {
96 | if (React.isValidElement(icon)) {
97 | content = icon;
98 | } else if (typeof icon === 'string') {
99 | const Icon = iconSource;
100 | content = ;
101 | } else {
102 | content = ;
103 | }
104 | }
105 |
106 | return (
107 |
113 | {content}
114 |
115 | );
116 | }
117 | }
118 |
119 | function createStyles() {
120 | return StyleSheet.create({
121 | itemWrapper: {
122 | padding: 5,
123 | },
124 | itemGroup: {
125 | flexDirection: 'row',
126 | // alignItems: 'center',
127 | },
128 | itemText: {
129 | alignSelf: 'center',
130 | letterSpacing: 1,
131 | fontWeight: '500',
132 | ios: {
133 | fontSize: IOS_ITEM_TEXT_SIZE,
134 | },
135 | },
136 | });
137 | }
138 |
139 | module.exports = ItemWrapper;
140 |
--------------------------------------------------------------------------------
/src/components/images/AnimatedImage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const {
12 | ActivityIndicator,
13 | Animated,
14 | Image,
15 | StyleSheet,
16 | View,
17 | } = require('react-native');
18 | const { BaseComponent } = require('../../commons');
19 |
20 | class AnimatedImage extends BaseComponent {
21 | static displayName = 'AnimatedImage';
22 |
23 | static propTypes = {
24 | ...Image.propTypes,
25 | /**
26 | * Additional spacing styles for the container
27 | */
28 | containerStyle: PropTypes.object,
29 | /**
30 | * Style for the image component
31 | */
32 | imageStyle: PropTypes.object,
33 | /**
34 | * The image source (external or assets)
35 | */
36 | source: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
37 | /**
38 | * Duration for the fade animation when the image is loaded
39 | */
40 | animationDuration: PropTypes.number,
41 | /**
42 | * Use to identify the avatar in tests
43 | */
44 | testId: PropTypes.string,
45 | /**
46 | * A component to render while the image is loading
47 | */
48 | loader: PropTypes.element,
49 | };
50 |
51 | static defaultProps = {
52 | animationDuration: 300,
53 | loader: ,
54 | };
55 |
56 | constructor(props) {
57 | super(props);
58 |
59 | this.state = {
60 | opacity: new Animated.Value(0),
61 | isLoading: true,
62 | };
63 | }
64 |
65 | onLoad() {
66 | this.setState({ isLoading: false }, () => {
67 | const animationParams = {
68 | toValue: 1,
69 | duration: this.props.animationDuration,
70 | useNativeDriver: false,
71 | };
72 | Animated.timing(this.state.opacity, animationParams).start();
73 | });
74 |
75 | this.props.onLoad && this.props.onLoad();
76 | }
77 |
78 | render() {
79 | const { testId, containerStyle, imageStyle, loader, ...props } = this.props;
80 | return (
81 |
82 | this.onLoad()}
86 | />
87 | {this.state.isLoading && loader && (
88 |
89 | {loader}
90 |
91 | )}
92 |
93 | );
94 | }
95 | }
96 |
97 | const styles = StyleSheet.create({
98 | loadingContainer: {
99 | position: 'absolute',
100 | top: 0,
101 | bottom: 0,
102 | left: 0,
103 | right: 0,
104 | alignItems: 'center',
105 | },
106 | loadingInner: {
107 | flex: 1,
108 | alignItems: 'center',
109 | justifyContent: 'center',
110 | },
111 | });
112 |
113 | module.exports = AnimatedImage;
114 |
--------------------------------------------------------------------------------
/src/components/images/Image.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const hoistNonReactStatic = require('hoist-non-react-statics');
12 | const _ = require('lodash');
13 | const RNImage = require('react-native').Image;
14 |
15 | const Assets = require('../../assets');
16 | const { BaseComponent } = require('../../commons');
17 | const { ThemeManager } = require('../../style');
18 |
19 | /**
20 | * @description: Image wrapper with extra functionality like source transform and assets support
21 | * @extends: Image
22 | * @extendslink: https://facebook.github.io/react-native/docs/image.html
23 | */
24 | class Image extends BaseComponent {
25 | static displayName = 'Image';
26 |
27 | static propTypes = {
28 | /**
29 | * custom source transform handler for manipulating the image source (great for size control)
30 | */
31 | sourceTransformer: PropTypes.func,
32 | /**
33 | * if provided image source we be drriven from asset name
34 | */
35 | assetName: PropTypes.string,
36 | /**
37 | * the asset group, default is "icons"
38 | */
39 | assetGroup: PropTypes.string,
40 | };
41 |
42 | static defaultProps = {
43 | assetGroup: 'icons',
44 | };
45 |
46 | constructor(props) {
47 | super(props);
48 |
49 | this.sourceTransformer =
50 | props.sourceTransformer ||
51 | _.get(ThemeManager.components, 'Image.sourceTransformer');
52 | }
53 |
54 | getImageSource() {
55 | const { assetName, assetGroup } = this.props;
56 | if (!_.isUndefined(assetName)) {
57 | return _.get(Assets, `${assetGroup}.${assetName}`);
58 | }
59 |
60 | if (this.sourceTransformer) {
61 | return this.sourceTransformer(this.props);
62 | }
63 |
64 | const { source } = this.props;
65 | if (_.get(source, 'uri') === null || _.get(source, 'uri') === '') {
66 | return { ...source, uri: undefined };
67 | }
68 |
69 | return source;
70 | }
71 |
72 | render() {
73 | const source = this.getImageSource();
74 | return ;
75 | }
76 | }
77 |
78 | hoistNonReactStatic(Image, RNImage);
79 |
80 | module.exports = Image;
81 |
--------------------------------------------------------------------------------
/src/components/images/NetworkImage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 |
12 | const AnimatedImage = require('./AnimatedImage');
13 | const { BaseComponent } = require('../../commons');
14 |
15 | class NetworkImage extends BaseComponent {
16 | static displayName = 'NetworkImage';
17 |
18 | static propTypes = {
19 | ...AnimatedImage.propTypes,
20 | /**
21 | * The fallback image source (external or assets)
22 | */
23 | fallbackSource: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
24 | };
25 |
26 | constructor(props) {
27 | super(props);
28 |
29 | this.state = {
30 | error: false,
31 | };
32 |
33 | this.onError = this.onError.bind(this);
34 | }
35 |
36 | onError() {
37 | this.setState({ error: true });
38 |
39 | this.props.onError && this.props.onError();
40 | }
41 |
42 | render() {
43 | const { fallbackSource, source, ...props } = this.props;
44 | return (
45 |
50 | );
51 | }
52 | }
53 |
54 | module.exports = NetworkImage;
55 |
--------------------------------------------------------------------------------
/src/components/images/__test__/Image.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const Image = require('../Image');
10 | const Assets = require('../../../assets');
11 | const { ThemeManager } = require('../../../style');
12 |
13 | describe('Image', () => {
14 | beforeEach(() => {
15 | ThemeManager.setComponentTheme('Image', {});
16 | });
17 |
18 | describe('getImageSource', () => {
19 | it('should return source prop, if no transformer was sent', () => {
20 | const uut = new Image({ source: 1 });
21 | expect(uut.getImageSource()).toBe(1);
22 | });
23 |
24 | it('should return transformed source prop, according to sourceTransform prop', () => {
25 | const sourceTransformer = jest.fn(() => 2);
26 | const uut = new Image({ source: 1, sourceTransformer });
27 | expect(uut.getImageSource()).toBe(2);
28 | });
29 |
30 | it('should return transformed source prop, according to sourceTransform in ThemeManager', () => {
31 | ThemeManager.setTheme({
32 | components: {
33 | Image: {
34 | sourceTransformer: jest.fn(() => 3),
35 | },
36 | },
37 | });
38 | const uut = new Image({ source: 1 });
39 | expect(uut.getImageSource()).toBe(3);
40 | });
41 |
42 | it('should return transformed source prop, according to sourceTransform prop and other given props', () => {
43 | const sourceTransformer = jest.fn(({ size, source }) =>
44 | size === 'small' ? source : 3,
45 | );
46 | let uut = new Image({ source: 1, size: 'small', sourceTransformer });
47 | expect(uut.getImageSource()).toBe(1);
48 | uut = new Image({ source: 1, size: 'large', sourceTransformer });
49 | expect(uut.getImageSource()).toBe(3);
50 | });
51 |
52 | it('should return asset according to assetName', () => {
53 | Assets.loadAssetsGroup('icons', {
54 | test: 'test.png',
55 | });
56 |
57 | Assets.loadAssetsGroup('icons.general', {
58 | test: 'test.png',
59 | });
60 |
61 | let uut = new Image({ assetGroup: 'icons', assetName: 'test' });
62 | expect(uut.getImageSource()).toBe('test.png');
63 |
64 | uut = new Image({ assetGroup: 'icons.general', assetName: 'test' });
65 | expect(uut.getImageSource()).toBe('test.png');
66 | });
67 |
68 | it('should handle when source sent with uri=null', () => {
69 | const uut = new Image({ source: { uri: null } });
70 | expect(uut.getImageSource()).toEqual({ uri: undefined });
71 | });
72 |
73 | it('should handle when source sent with uri is empty string', () => {
74 | const uut = new Image({ source: { uri: '' } });
75 | expect(uut.getImageSource()).toEqual({ uri: undefined });
76 | });
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/src/components/images/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = {
10 | get AnimatedImage() {
11 | return require('./AnimatedImage');
12 | },
13 | get Image() {
14 | return require('./Image');
15 | },
16 | get NetworkImage() {
17 | return require('./NetworkImage');
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/src/components/img/add@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/add@2x.png
--------------------------------------------------------------------------------
/src/components/img/disclosure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/disclosure.png
--------------------------------------------------------------------------------
/src/components/img/disclosure@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/disclosure@2x.png
--------------------------------------------------------------------------------
/src/components/img/disclosure@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/disclosure@3x.png
--------------------------------------------------------------------------------
/src/components/img/filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/filter.png
--------------------------------------------------------------------------------
/src/components/img/filter@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/filter@2x.png
--------------------------------------------------------------------------------
/src/components/img/filter@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/filter@3x.png
--------------------------------------------------------------------------------
/src/components/img/hamburger-unread.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger-unread.png
--------------------------------------------------------------------------------
/src/components/img/hamburger-unread@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger-unread@2x.png
--------------------------------------------------------------------------------
/src/components/img/hamburger-unread@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger-unread@3x.png
--------------------------------------------------------------------------------
/src/components/img/hamburger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger.png
--------------------------------------------------------------------------------
/src/components/img/hamburger@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger@2x.png
--------------------------------------------------------------------------------
/src/components/img/hamburger@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/img/hamburger@3x.png
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | import { PageContainer } from './containers';
10 | import LoadingView from './loading';
11 | import Header from './header';
12 | import KeyboardSpacer from './other/KeyboardSpacer';
13 | import PageControl from './other/PageControl';
14 | import PureListView from './other/PureListView';
15 | import SegmentedControl from './other/SegmentedControl';
16 | import SettingsList from './SettingsList';
17 | import StyleSheet from './other/StyleSheet';
18 | import { TextArea, TextField, TextInput } from './inputs';
19 | import { Touchable } from './touchables';
20 |
21 | export {
22 | // Containers
23 | PageContainer,
24 | LoadingView,
25 | Header,
26 | // Inputs
27 | TextArea,
28 | TextField,
29 | TextInput,
30 | // Other
31 | KeyboardSpacer,
32 | PageControl,
33 | PureListView,
34 | SegmentedControl,
35 | SettingsList,
36 | StyleSheet,
37 | Touchable,
38 | };
39 |
--------------------------------------------------------------------------------
/src/components/inputs/BaseInput.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import PropTypes from 'prop-types';
3 | import 'react';
4 | import {
5 | TextInput as RNTextInput,
6 | Animated,
7 | ViewPropTypes,
8 | } from 'react-native';
9 | import { BaseComponent, Colors, Typography } from 'react-native-ui-lib';
10 |
11 | export default class BaseInput extends BaseComponent {
12 | static displayName = 'BaseInput';
13 | static propTypes = {
14 | ...RNTextInput.propTypes,
15 | ...BaseComponent.propTypes,
16 | /**
17 | * text color
18 | */
19 | color: PropTypes.string,
20 | /**
21 | * text input container style
22 | */
23 | containerStyle: ViewPropTypes.style,
24 | /**
25 | * Use to identify the component in tests
26 | */
27 | testId: PropTypes.string,
28 | };
29 |
30 | static defaultProps = {
31 | placeholderTextColor: Colors.dark60,
32 | };
33 |
34 | constructor(props) {
35 | super(props);
36 |
37 | this.onChangeText = this.onChangeText.bind(this);
38 | this.onChange = this.onChange.bind(this);
39 | this.onFocus = this.onFocus.bind(this);
40 | this.onBlur = this.onBlur.bind(this);
41 | this.focus = this.focus.bind(this);
42 |
43 | const typography = this.getTypography();
44 | this.state = {
45 | inputWidth: typography.fontSize * 2,
46 | value: props.value,
47 | floatingPlaceholderState: new Animated.Value(props.value ? 1 : 0),
48 | showExpandableModal: !false,
49 | };
50 | }
51 |
52 | getTypography() {
53 | return this.extractTypographyValue() || Typography.text70;
54 | }
55 |
56 | getUnderlineStyle() {
57 | const { focused } = this.state;
58 | const { error } = this.props;
59 | if (error) {
60 | return this.styles.errorUnderline;
61 | } else if (focused) {
62 | return this.styles.focusedUnderline;
63 | }
64 |
65 | return null;
66 | }
67 |
68 | hasText() {
69 | const { value } = this.state;
70 | return value && value.length > 0;
71 | }
72 |
73 | onFocus(...args) {
74 | _.invoke(this.props, 'onFocus', ...args);
75 | this.setState({ focused: true });
76 | }
77 |
78 | onBlur(...args) {
79 | _.invoke(this.props, 'onBlur', ...args);
80 | this.setState({ focused: false });
81 | }
82 |
83 | onChange(event) {
84 | _.invoke(this.props, 'onChange', event);
85 | }
86 |
87 | onChangeText(text) {
88 | _.invoke(this.props, 'onChangeText', text);
89 |
90 | this.setState({
91 | value: text,
92 | });
93 | }
94 |
95 | focus() {
96 | this.input.focus();
97 | }
98 |
99 | blur() {
100 | this.input.blur();
101 | }
102 |
103 | clear() {
104 | this.input.clear();
105 | }
106 |
107 | isFocused() {
108 | return this.input.isFocused();
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/components/inputs/TextArea.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | import React from 'react';
10 | import PropTypes from 'prop-types';
11 | import { View, TextInput as RNTextInput, StyleSheet } from 'react-native';
12 | import BaseInput from './BaseInput';
13 |
14 | export default class TextArea extends BaseInput {
15 | static displayName = 'TextArea';
16 | static propTypes = {
17 | ...RNTextInput.propTypes,
18 | ...BaseInput.propTypes,
19 | /**
20 | * make component rtl
21 | */
22 | rtl: PropTypes.bool,
23 | /**
24 | * Use to identify the component in tests
25 | */
26 | testId: PropTypes.string,
27 | };
28 |
29 | generateStyles() {
30 | this.styles = createStyles(this.props);
31 | }
32 |
33 | render() {
34 | const { value } = this.state;
35 | const typography = this.getTypography();
36 | const inputStyle = [this.styles.input, typography];
37 | return (
38 |
39 | {
47 | this.input = input;
48 | }}
49 | />
50 |
51 | );
52 | }
53 | }
54 |
55 | function createStyles({ rtl }) {
56 | return StyleSheet.create({
57 | container: {
58 | flex: 1,
59 | },
60 | input: {
61 | flex: 1,
62 | justifyContent: 'flex-start',
63 | alignItems: 'flex-start',
64 | textAlignVertical: 'top',
65 | textAlign: rtl ? 'right' : undefined,
66 | writingDirection: rtl ? 'rtl' : undefined,
67 | },
68 | });
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/inputs/__test__/TextField.spec.js:
--------------------------------------------------------------------------------
1 | import TextField from '../TextField';
2 | import { Colors } from 'react-native-ui-lib';
3 |
4 | describe('TextField', () => {
5 | // beforeEach(() => {});
6 |
7 | describe('shouldFakePlaceholder', () => {
8 | it('should shouldFakePlaceholder', () => {
9 | let uut = new TextField({});
10 | expect(uut.shouldFakePlaceholder()).toBe(false);
11 |
12 | uut = new TextField({ floatingPlaceholder: true });
13 | expect(uut.shouldFakePlaceholder()).toBe(true);
14 |
15 | uut = new TextField({ floatingPlaceholder: true, centered: true });
16 | expect(uut.shouldFakePlaceholder()).toBe(false);
17 | });
18 | });
19 |
20 | describe('getStateColor', () => {
21 | it('should return dark70 when blur (inactive)', () => {
22 | const uut = new TextField({});
23 | expect(uut.getStateColor(undefined, true)).toEqual(Colors.dark70);
24 | });
25 | it('should return red30 when error', () => {
26 | const uut = new TextField({ error: 'test error' });
27 | expect(uut.getStateColor(undefined, true)).toEqual(Colors.red30);
28 | });
29 | it('should return blue30 when focused', () => {
30 | const uut = new TextField({});
31 | uut.state = { focused: true };
32 | expect(uut.getStateColor(undefined, true)).toEqual(Colors.blue30);
33 | });
34 |
35 | const underlines = {
36 | default: Colors.cyan40,
37 | focus: Colors.orange60,
38 | error: Colors.purple50,
39 | };
40 | it('should return cyan40 when passing underlineColor and when blur (inactive)', () => {
41 | const uut = new TextField({ underlineColor: underlines });
42 | expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(
43 | Colors.cyan40,
44 | );
45 | });
46 | it('should return purple50 when passing underlineColor and when error', () => {
47 | const uut = new TextField({
48 | underlineColor: underlines,
49 | error: 'test error',
50 | });
51 | expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(
52 | Colors.purple50,
53 | );
54 | });
55 | it('should return orange60 when passing underlineColor and when focused', () => {
56 | const uut = new TextField({ underlineColor: underlines });
57 | uut.state = { focused: true };
58 | expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(
59 | Colors.orange60,
60 | );
61 | });
62 | });
63 |
64 | describe('getCharCount', () => {
65 | it('should return 5 when value is "inbal"', () => {
66 | const uut = new TextField({ value: 'inbal' });
67 | expect(uut.getCharCount()).toBe(5);
68 | });
69 | });
70 |
71 | describe('isCounterLimit', () => {
72 | it('should return true when character count = 10 and maxLength = 10', () => {
73 | const uut = new TextField({ maxLength: 10 });
74 | jest.spyOn(uut, 'getCharCount').mockImplementation(() => 10);
75 | expect(uut.isCounterLimit()).toBe(true);
76 | expect(uut.getCharCount).toHaveBeenCalledTimes(1);
77 | });
78 | it('should return false when character count = 5 and maxLength = 10', () => {
79 | const uut = new TextField({ maxLength: 10 });
80 | jest.spyOn(uut, 'getCharCount').mockImplementation(() => 5);
81 | expect(uut.isCounterLimit()).toBe(false);
82 | expect(uut.getCharCount).toHaveBeenCalledTimes(1);
83 | });
84 | });
85 | });
86 |
--------------------------------------------------------------------------------
/src/components/inputs/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | import TextArea from './TextArea';
10 | import TextField from './TextField';
11 | import TextInput from './TextInput';
12 |
13 | export { TextArea, TextField, TextInput };
14 |
--------------------------------------------------------------------------------
/src/components/loading/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { ActivityIndicator, StyleSheet } = require('react-native');
12 | const {
13 | Constants,
14 | Colors,
15 | Text,
16 | ThemeManager,
17 | View,
18 | } = require('react-native-ui-lib');
19 |
20 | class LoadingView extends React.Component {
21 | static displayName = 'LoadingView';
22 |
23 | static propTypes = {
24 | ...ActivityIndicator.propTypes,
25 | /**
26 | * Show the screen as an absolute overlay
27 | */
28 | overlay: PropTypes.bool,
29 | /**
30 | * is loading
31 | */
32 | loading: PropTypes.bool,
33 | /**
34 | * loading caption
35 | */
36 | caption: PropTypes.string,
37 | /**
38 | * caption style
39 | */
40 | captionStyle: PropTypes.oneOfType([
41 | PropTypes.object,
42 | PropTypes.number,
43 | PropTypes.array,
44 | ]),
45 | /**
46 | * container style
47 | */
48 | containerStyle: PropTypes.oneOfType([
49 | PropTypes.object,
50 | PropTypes.number,
51 | PropTypes.array,
52 | ]),
53 | };
54 |
55 | static defaultProps = {
56 | overlay: false,
57 | loading: true,
58 | color: Constants.isIOS ? Colors.dark60 : ThemeManager.primaryColor,
59 | caption: 'Loading...',
60 | };
61 |
62 | render() {
63 | const {
64 | overlay,
65 | caption,
66 | captionStyle,
67 | style,
68 | containerStyle,
69 | ...props
70 | } = this.props;
71 |
72 | if (!this.props.loading) {
73 | return null;
74 | }
75 |
76 | return (
77 |
84 |
85 | {caption && (
86 |
87 | {caption}
88 |
89 | )}
90 |
91 | );
92 | }
93 | }
94 |
95 | const styles = StyleSheet.create({
96 | container: {
97 | flex: 1,
98 | },
99 | overlayContainer: {
100 | ...StyleSheet.absoluteFillObject,
101 | backgroundColor: Colors.rgba(Colors.white, 0.85),
102 | zIndex: 100,
103 | },
104 | containerCommon: {
105 | alignItems: 'center',
106 | justifyContent: 'center',
107 | paddingHorizontal: 10,
108 | },
109 | indicator: {
110 | transform: [{ scale: 1.5 }],
111 | },
112 | caption: {
113 | marginTop: 15,
114 | color: Colors.dark10,
115 | },
116 | });
117 |
118 | module.exports = LoadingView;
119 |
--------------------------------------------------------------------------------
/src/components/multiple-shadow/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { StyleSheet } = require('react-native');
12 |
13 | const View = require('../view');
14 | const { BaseComponent } = require('../../commons');
15 | const { Shadows } = require('../../style');
16 |
17 | /**
18 | * @description: A multiple layer for multiple shadow effect for iOS only
19 | */
20 | class MultipleShadow extends BaseComponent {
21 | static displayName = 'IGNORE';
22 | static propTypes = {
23 | /**
24 | * top shadow style to use
25 | */
26 | topShadow: PropTypes.object,
27 | /**
28 | * bottom shadow style to use
29 | */
30 | bottomShadow: PropTypes.object,
31 | /**
32 | * a combination of top and bottom shadow based on shadow presets names
33 | */
34 | shadowType: PropTypes.oneOf(Object.keys(Shadows)),
35 | /**
36 | * Custom shadow color to be applied on both top and bottom shadows
37 | */
38 | shadowColor: PropTypes.string,
39 | };
40 |
41 | static defaultProps = {
42 | shadowType: 'white40',
43 | };
44 |
45 | generateStyles() {
46 | this.styles = createStyles(this.props);
47 | }
48 |
49 | getShadowStyles() {
50 | const { shadowType } = this.props;
51 | let { topShadow, bottomShadow } = this.props;
52 |
53 | if (!topShadow && Shadows[shadowType]) {
54 | topShadow = Shadows[shadowType].top;
55 | }
56 |
57 | if (!bottomShadow && Shadows[shadowType]) {
58 | bottomShadow = Shadows[shadowType].bottom;
59 | }
60 |
61 | return { topShadow, bottomShadow };
62 | }
63 |
64 | render() {
65 | const { style, shadowColor, ...others } = this.props;
66 | const { topShadow, bottomShadow } = this.getShadowStyles();
67 | return (
68 |
77 |
86 | {this.props.children}
87 |
88 |
89 | );
90 | }
91 | }
92 |
93 | function createStyles() {
94 | return StyleSheet.create({
95 | wrapper: {
96 | flexGrow: 1,
97 | },
98 | });
99 | }
100 |
101 | module.exports = MultipleShadow;
102 |
--------------------------------------------------------------------------------
/src/components/nav-icons/BackIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/back.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/BackWhiteIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/back_white.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/ForwardIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/forward.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/ForwardWhiteIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/forward_white.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/XIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/x.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/XWhiteIcon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./img/x-white.png');
10 |
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back@2x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back@2x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back@3x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back@3x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back@3x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white@2x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white@2x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white@3x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/back_white@3x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/back_white@3x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward@2x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward@2x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward@3x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward@3x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward@3x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white@2x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white@2x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white@3x.android.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/forward_white@3x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/forward_white@3x.ios.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x-white.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x-white@2x.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x-white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x-white@3x.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x@2x.png
--------------------------------------------------------------------------------
/src/components/nav-icons/img/x@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rghorbani/react-native-common/68cc77ae42b4f74f18cc29d860893ce57758ea5e/src/components/nav-icons/img/x@3x.png
--------------------------------------------------------------------------------
/src/components/nav-icons/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | module.exports = {
8 | get BackIcon() {
9 | return require('./BackIcon');
10 | },
11 | get BackWhiteIcon() {
12 | return require('./BackWhiteIcon');
13 | },
14 | get ForwardIcon() {
15 | return require('./ForwardIcon');
16 | },
17 | get ForwardWhiteIcon() {
18 | return require('./ForwardWhiteIcon');
19 | },
20 | get XIcon() {
21 | return require('./XIcon');
22 | },
23 | get XWhiteIcon() {
24 | return require('./XWhiteIcon');
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/src/components/other/ItemsWithSeparator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { PixelRatio, StyleSheet, View, ViewPropTypes } = require('react-native');
12 |
13 | class ItemsWithSeparator extends React.Component {
14 | static displayName = 'ItemsWithSeparator';
15 |
16 | static propTypes = {
17 | style: ViewPropTypes.style,
18 | separatorStyle: ViewPropTypes.style,
19 | children: PropTypes.nodes,
20 | };
21 |
22 | render() {
23 | let children = [];
24 | let length = React.Children.count(this.props.children);
25 | React.Children.forEach(this.props.children, (child, ii) => {
26 | children.push(child);
27 | if (ii !== length - 1) {
28 | children.push(
29 | ,
33 | );
34 | }
35 | });
36 | return {children};
37 | }
38 | }
39 |
40 | const styles = StyleSheet.create({
41 | separator: {
42 | backgroundColor: '#0322500A',
43 | height: 1 / PixelRatio.get(),
44 | },
45 | });
46 |
47 | module.exports = ItemsWithSeparator;
48 |
--------------------------------------------------------------------------------
/src/components/other/KeyboardSpacer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const {
12 | Dimensions,
13 | Platform,
14 | Keyboard,
15 | LayoutAnimation,
16 | StyleSheet,
17 | View,
18 | ViewPropTypes,
19 | } = require('react-native');
20 |
21 | // From: https://medium.com/man-moon/writing-modern-react-native-ui-e317ff956f02
22 | const defaultAnimation = {
23 | duration: 500,
24 | create: {
25 | duration: 300,
26 | type: LayoutAnimation.Types.easeInEaseOut,
27 | property: LayoutAnimation.Properties.opacity,
28 | },
29 | update: {
30 | type: LayoutAnimation.Types.spring,
31 | springDamping: 200,
32 | },
33 | };
34 |
35 | class KeyboardSpacer extends React.Component {
36 | static displayName = 'KeyboardSpacer';
37 |
38 | static propTypes = {
39 | topSpacing: PropTypes.number,
40 | onToggle: PropTypes.func,
41 | style: ViewPropTypes.style,
42 | };
43 |
44 | static defaultProps = {
45 | topSpacing: 0,
46 | onToggle: () => null,
47 | };
48 |
49 | constructor(props, context) {
50 | super(props, context);
51 | this.state = {
52 | keyboardSpace: 0,
53 | isKeyboardOpened: false,
54 | };
55 | this._listeners = null;
56 | this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this);
57 | this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this);
58 | }
59 |
60 | componentDidMount() {
61 | const updateListener =
62 | Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow';
63 | const resetListener =
64 | Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide';
65 | this._listeners = [
66 | Keyboard.addListener(updateListener, this.updateKeyboardSpace),
67 | Keyboard.addListener(resetListener, this.resetKeyboardSpace),
68 | ];
69 | }
70 |
71 | componentWillUnmount() {
72 | this._listeners.forEach(listener => listener.remove());
73 | }
74 |
75 | updateKeyboardSpace(event) {
76 | if (!event.endCoordinates) {
77 | return;
78 | }
79 |
80 | let animationConfig = defaultAnimation;
81 | if (Platform.OS === 'ios') {
82 | animationConfig = LayoutAnimation.create(
83 | event.duration,
84 | LayoutAnimation.Types[event.easing],
85 | LayoutAnimation.Properties.opacity,
86 | );
87 | }
88 | LayoutAnimation.configureNext(animationConfig);
89 |
90 | // get updated on rotation
91 | const screenHeight = Dimensions.get('window').height;
92 | // when external physical keyboard is connected
93 | // event.endCoordinates.height still equals virtual keyboard height
94 | // however only the keyboard toolbar is showing if there should be one
95 | const keyboardSpace =
96 | screenHeight - event.endCoordinates.screenY + this.props.topSpacing;
97 | this.setState(
98 | {
99 | keyboardSpace,
100 | isKeyboardOpened: true,
101 | },
102 | this.props.onToggle(true, keyboardSpace),
103 | );
104 | }
105 |
106 | resetKeyboardSpace(event) {
107 | let animationConfig = defaultAnimation;
108 | if (Platform.OS === 'ios') {
109 | animationConfig = LayoutAnimation.create(
110 | event.duration,
111 | LayoutAnimation.Types[event.easing],
112 | LayoutAnimation.Properties.opacity,
113 | );
114 | }
115 | LayoutAnimation.configureNext(animationConfig);
116 |
117 | this.setState(
118 | {
119 | keyboardSpace: 0,
120 | isKeyboardOpened: false,
121 | },
122 | this.props.onToggle(false, 0),
123 | );
124 | }
125 |
126 | render() {
127 | return (
128 |
135 | );
136 | }
137 | }
138 |
139 | const styles = StyleSheet.create({
140 | container: {
141 | left: 0,
142 | right: 0,
143 | bottom: 0,
144 | },
145 | });
146 |
147 | module.exports = KeyboardSpacer;
148 |
--------------------------------------------------------------------------------
/src/components/other/PageControl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const { StyleSheet, View, ViewPropTypes } = require('react-native');
12 |
13 | class PageControl extends React.Component {
14 | static displayName = 'PageControl';
15 |
16 | static propTypes = {
17 | count: PropTypes.number.isRequired,
18 | selectedIndex: PropTypes.number.isRequired,
19 | fullColor: PropTypes.string,
20 | emptyColor: PropTypes.string,
21 | size: PropTypes.number,
22 | style: ViewPropTypes.style,
23 | };
24 |
25 | render() {
26 | let images = [];
27 | for (let i = 0; i < this.props.count; i++) {
28 | const isSelected = this.props.selectedIndex === i;
29 | images.push();
30 | }
31 | return (
32 |
33 | {images}
34 |
35 | );
36 | }
37 | }
38 |
39 | class Circle extends React.Component {
40 | static displayName = 'PageControl.Circle';
41 |
42 | static propTypes = {
43 | fullColor: PropTypes.string,
44 | emptyColor: PropTypes.string,
45 | size: PropTypes.number,
46 | };
47 |
48 | render() {
49 | let extraStyle = {};
50 | if (this.props.isSelected) {
51 | extraStyle = this.props.fullColor
52 | ? { backgroundColor: this.props.fullColor }
53 | : styles.full;
54 | } else {
55 | extraStyle = this.props.emptyColor
56 | ? { backgroundColor: this.props.emptyColor }
57 | : styles.empty;
58 | }
59 | if (this.props.size) {
60 | extraStyle = {
61 | ...extraStyle,
62 | width: this.props.size,
63 | height: this.props.size,
64 | borderRadius: this.props.size / 2,
65 | };
66 | }
67 | return ;
68 | }
69 | }
70 |
71 | const CIRCLE_SIZE = 4;
72 |
73 | const styles = StyleSheet.create({
74 | container: {
75 | alignItems: 'center',
76 | justifyContent: 'center',
77 | },
78 | innerContainer: {
79 | flexDirection: 'row',
80 | },
81 | circle: {
82 | margin: 2,
83 | width: CIRCLE_SIZE,
84 | height: CIRCLE_SIZE,
85 | borderRadius: CIRCLE_SIZE / 2,
86 | },
87 | full: {
88 | backgroundColor: '#fff',
89 | },
90 | empty: {
91 | backgroundColor: '#fff5',
92 | },
93 | });
94 |
95 | module.exports = PageControl;
96 | module.exports.__cards__ = define => {
97 | define('Simple 2', () => );
98 | define('Simple 5', () => );
99 | };
100 |
--------------------------------------------------------------------------------
/src/components/other/PureListView.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const {
12 | FlatList,
13 | SectionList,
14 | SwipeableFlatList,
15 | ViewPropTypes,
16 | } = require('react-native');
17 |
18 | class PureListView extends React.PureComponent {
19 | static displayName = 'PureListView';
20 |
21 | static propTypes = {
22 | type: PropTypes.oneOf(['FlatList', 'SectionList', 'SwipeableFlatList'])
23 | .isRequired,
24 | data: PropTypes.array.isRequired,
25 | renderEmptyList: PropTypes.func,
26 | style: ViewPropTypes.style,
27 | };
28 |
29 | static defaultProps = {
30 | type: 'FlatList',
31 | data: [],
32 | renderEmptyList: null,
33 | };
34 |
35 | render() {
36 | const { renderEmptyList, type, ...props } = this.props;
37 | if (this.props.data.length === 0) {
38 | return renderEmptyList && renderEmptyList();
39 | }
40 |
41 | if (type === 'SectionList') {
42 | return ;
43 | } else if (type === 'SwipeableFlatList') {
44 | return ;
45 | }
46 |
47 | return ;
48 | }
49 | }
50 |
51 | module.exports = PureListView;
52 |
--------------------------------------------------------------------------------
/src/components/other/SegmentedControl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const {
12 | Platform,
13 | Text,
14 | TouchableOpacity,
15 | View,
16 | ViewPropTypes,
17 | } = require('react-native');
18 |
19 | import StyleSheet from './StyleSheet';
20 |
21 | class SegmentedControl extends React.Component {
22 | static displayName = 'PageControl';
23 |
24 | static propTypes: {
25 | values: PropTypes.array,
26 | selectionColor: PropTypes.string,
27 | selectedIndex: PropTypes.number,
28 | onChange: PropTypes.func,
29 | titleStyle: PropTypes.any,
30 | segmentStyle: PropTypes.any,
31 | style: ViewPropTypes.style,
32 | };
33 |
34 | render() {
35 | let segments = this.props.values.map((value, index) => (
36 | this.props.onChange(index)}
44 | />
45 | ));
46 | return {segments};
47 | }
48 | }
49 |
50 | class Segment extends React.Component {
51 | props: {
52 | value: string,
53 | isSelected: boolean,
54 | selectionColor: string,
55 | segmentStyle?: any,
56 | titleStyle?: any,
57 | onPress: () => void,
58 | };
59 |
60 | render() {
61 | let selectedButtonStyle;
62 | if (this.props.isSelected) {
63 | selectedButtonStyle = { borderColor: this.props.selectionColor };
64 | }
65 | let deselectedLabelStyle;
66 | if (!this.props.isSelected && Platform.OS === 'android') {
67 | deselectedLabelStyle = styles.deselectedLabel;
68 | }
69 | let title = this.props.value && this.props.value.toUpperCase();
70 |
71 | let accessibilityTraits = ['button'];
72 | if (this.props.isSelected) {
73 | accessibilityTraits.push('selected');
74 | }
75 |
76 | return (
77 |
83 |
84 | {title}
85 |
86 |
87 | );
88 | }
89 | }
90 |
91 | const HEIGHT = 32;
92 |
93 | const styles = StyleSheet.create({
94 | container: {
95 | flexDirection: 'row',
96 | backgroundColor: 'transparent',
97 | ios: {
98 | paddingBottom: 6,
99 | justifyContent: 'center',
100 | alignItems: 'center',
101 | },
102 | android: {
103 | paddingLeft: 60,
104 | },
105 | },
106 | button: {
107 | borderColor: 'transparent',
108 | alignItems: 'center',
109 | justifyContent: 'center',
110 | backgroundColor: 'transparent',
111 | ios: {
112 | height: HEIGHT,
113 | paddingHorizontal: 20,
114 | borderRadius: HEIGHT / 2,
115 | borderWidth: 1,
116 | },
117 | android: {
118 | paddingBottom: 6,
119 | paddingHorizontal: 10,
120 | borderBottomWidth: 3,
121 | marginRight: 10,
122 | },
123 | },
124 | label: {
125 | letterSpacing: 1,
126 | fontSize: 12,
127 | color: 'white',
128 | },
129 | deselectedLabel: {
130 | color: 'rgba(255, 255, 255, 0.7)',
131 | },
132 | });
133 |
134 | module.exports = SegmentedControl;
135 |
--------------------------------------------------------------------------------
/src/components/other/StyleSheet.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const { Platform, StyleSheet } = require('react-native');
10 |
11 | function create(styles: Object): { [name: string]: number } {
12 | const platformStyles = {};
13 | Object.keys(styles).forEach(name => {
14 | let { ios, android, ...style } = { ...styles[name] };
15 | if (ios && Platform.OS === 'ios') {
16 | style = { ...style, ...ios };
17 | }
18 | if (android && Platform.OS === 'android') {
19 | style = { ...style, ...android };
20 | }
21 | platformStyles[name] = style;
22 | });
23 | return StyleSheet.create(platformStyles);
24 | }
25 |
26 | export default {
27 | create,
28 | };
29 |
--------------------------------------------------------------------------------
/src/components/picker/NativePicker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const _ = require('lodash');
11 | const PickerDialog = require('./PickerDialog');
12 | const TextInput = require('../inputs/TextInput');
13 | const WheelPicker = require('../../native-components/wheelpicker');
14 | const { BaseComponent } = require('../../commons');
15 |
16 | class Picker extends BaseComponent {
17 | constructor(props) {
18 | super(props);
19 |
20 | this.state = {
21 | selectedValue: this.props.value,
22 | items: this.extractPickerItems(this.props),
23 | };
24 |
25 | this.onCancel = this.onCancel.bind(this);
26 | this.onDone = this.onDone.bind(this);
27 | this.onValueChange = this.onValueChange.bind(this);
28 | this.renderPickerDialog = this.renderPickerDialog.bind(this);
29 | }
30 |
31 | extractPickerItems(props) {
32 | const { children, useNativePicker } = props;
33 | if (useNativePicker) {
34 | const items = React.Children.map(children, child => ({
35 | value: child.props.value,
36 | label: child.props.label,
37 | }));
38 | return items;
39 | }
40 | }
41 |
42 | onCancel() {
43 | this.setState({
44 | selectedValue: this.props.value,
45 | });
46 | this.input.toggleExpandableModal(false);
47 | }
48 |
49 | onDone() {
50 | const { selectedValue } = this.state;
51 | _.invoke(this.props, 'onChange', selectedValue);
52 | this.input.toggleExpandableModal(false);
53 | }
54 |
55 | onValueChange(selectedValue) {
56 | this.setState({
57 | selectedValue,
58 | });
59 | }
60 |
61 | getLabel() {
62 | const { value, getLabel } = this.props;
63 |
64 | if (_.isFunction(getLabel)) {
65 | return getLabel(value);
66 | }
67 |
68 | const { items } = this.state;
69 | const selectedItem = _.find(items, { value });
70 | return _.get(selectedItem, 'label');
71 | }
72 |
73 | renderPickerDialog() {
74 | const { selectedValue } = this.state;
75 | return (
76 |
84 | );
85 | }
86 |
87 | render() {
88 | const textInputProps = TextInput.extractOwnProps(this.props);
89 | const label = this.getLabel();
90 | return (
91 | (this.input = r)}
93 | floatingPlaceholder={false}
94 | enableErrors={false}
95 | {...textInputProps}
96 | value={label}
97 | expandable
98 | editable={false}
99 | renderExpandable={this.renderPickerDialog}
100 | />
101 | );
102 | }
103 | }
104 |
105 | Picker.Item = WheelPicker.Item;
106 |
107 | module.exports = Picker;
108 |
--------------------------------------------------------------------------------
/src/components/picker/PickerDialog.android.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const _ = require('lodash');
12 | const { StyleSheet } = require('react-native');
13 |
14 | const Dialog = require('../dialog');
15 | const Text = require('../text');
16 | const View = require('../view');
17 | const WheelPicker = require('../../native-components/wheelpicker');
18 | const { BaseComponent } = require('../../commons');
19 | const { BorderRadiuses, Colors } = require('../../style');
20 |
21 | class PickerDialog extends BaseComponent {
22 | static propTypes = {
23 | selectedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
24 | onValueChange: PropTypes.func,
25 | onDone: PropTypes.func,
26 | onCancel: PropTypes.func,
27 | children: PropTypes.array,
28 | };
29 |
30 | state = {};
31 |
32 | renderHeader() {
33 | const { topBarProps } = this.props;
34 | const title = _.get(topBarProps, 'title');
35 | const titleStyle = _.get(topBarProps, 'titleStyle');
36 |
37 | if (title) {
38 | return (
39 |
40 |
41 | {title}
42 |
43 |
44 | );
45 | }
46 | }
47 |
48 | renderFooter() {
49 | const { onDone, onCancel, topBarProps } = this.props;
50 | const doneLabel = _.get(topBarProps, 'doneLabel', 'OK');
51 | const cancelLabel = _.get(topBarProps, 'cancelLabel', 'CANCEL');
52 |
53 | return (
54 |
55 |
56 | {cancelLabel}
57 |
58 |
59 | {doneLabel}
60 |
61 |
62 | );
63 | }
64 |
65 | renderPicker() {
66 | const {
67 | children,
68 | onValueChange,
69 | selectedValue,
70 | renderNativePicker,
71 | } = this.props;
72 | if (_.isFunction(renderNativePicker)) {
73 | return renderNativePicker(this.props);
74 | }
75 | return (
76 |
77 | {children}
78 |
79 | );
80 | }
81 |
82 | render() {
83 | const dialogProps = Dialog.extractOwnProps(this.props);
84 | return (
85 |
94 | );
95 | }
96 | }
97 |
98 | const styles = StyleSheet.create({
99 | dialog: {
100 | flex: 1,
101 | backgroundColor: Colors.white,
102 | overflow: 'hidden',
103 | borderRadius: BorderRadiuses.br10,
104 | paddingHorizontal: 24,
105 | },
106 | header: {
107 | paddingTop: 21,
108 | },
109 | footer: {
110 | height: 52,
111 | flexDirection: 'row',
112 | justifyContent: 'flex-end',
113 | alignItems: 'center',
114 | },
115 | });
116 |
117 | module.exports = PickerDialog;
118 |
--------------------------------------------------------------------------------
/src/components/picker/PickerDialog.ios.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const _ = require('lodash');
12 | const { StyleSheet } = require('react-native');
13 |
14 | const Dialog = require('../dialog');
15 | const View = require('../view');
16 | const Text = require('../text');
17 | const WheelPicker = require('../../native-components/wheelpicker');
18 | const { BaseComponent } = require('../../commons');
19 | const { Colors } = require('../../style');
20 |
21 | class PickerDialog extends BaseComponent {
22 | static propTypes = {
23 | selectedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
24 | onValueChange: PropTypes.func,
25 | onDone: PropTypes.func,
26 | onCancel: PropTypes.func,
27 | topBarProps: PropTypes.object,
28 | children: PropTypes.array,
29 | };
30 |
31 | state = {};
32 |
33 | renderHeader() {
34 | const { onDone, onCancel, topBarProps } = this.props;
35 |
36 | return (
37 |
38 |
39 | {_.get(topBarProps, 'cancelLabel', 'Cancel')}
40 |
41 |
42 | {_.get(topBarProps, 'doneLabel', 'Done')}
43 |
44 |
45 | );
46 | }
47 |
48 | renderPicker() {
49 | const {
50 | children,
51 | onValueChange,
52 | selectedValue,
53 | renderNativePicker,
54 | } = this.props;
55 | if (_.isFunction(renderNativePicker)) {
56 | return renderNativePicker(this.props);
57 | }
58 | return (
59 |
60 | {children}
61 |
62 | );
63 | }
64 |
65 | render() {
66 | const dialogProps = Dialog.extractOwnProps(this.props);
67 | return (
68 |
83 | );
84 | }
85 | }
86 |
87 | const styles = StyleSheet.create({
88 | header: {
89 | height: 44,
90 | backgroundColor: Colors.dark80,
91 | paddingHorizontal: 17,
92 | flexDirection: 'row',
93 | justifyContent: 'space-between',
94 | alignItems: 'center',
95 | },
96 | });
97 |
98 | module.exports = PickerDialog;
99 |
--------------------------------------------------------------------------------
/src/components/picker/PickerItem.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const PropTypes = require('prop-types');
11 | const _ = require('lodash');
12 | const { Image, StyleSheet } = require('react-native');
13 |
14 | const View = require('../view');
15 | const Text = require('../text');
16 | const Assets = require('../../assets');
17 | const { TouchableOpacity } = require('../touchables');
18 | const { BaseComponent } = require('../../commons');
19 | const { Colors, Typography, ThemeManager } = require('../../style');
20 |
21 | // TODO: deprecate passing an an object as a value, use label and value props separately
22 | /**
23 | * @description: Picker.Item, for configuring the Picker's selectable options
24 | * @extends: TouchableOpacity
25 | * @extendslink: docs/TouchableOpacity
26 | */
27 | class PickerItem extends BaseComponent {
28 | static displayName = 'Picker.Item';
29 |
30 | static propTypes = {
31 | /**
32 | * [DEPRECATED - please include the label in the value prop] The item label
33 | */
34 | label: PropTypes.string,
35 | /**
36 | * The item value with the following format - {value: ..., label: ...},
37 | * for custom shape use getItemLabel, getItemValue props
38 | */
39 | value: PropTypes.oneOfType([
40 | PropTypes.object,
41 | PropTypes.string,
42 | PropTypes.number,
43 | ]),
44 | /**
45 | * Function to return the label out of the item value prop when value is custom shaped.
46 | */
47 | getItemLabel: PropTypes.func,
48 | /**
49 | * Function to return the value out of the item value prop when value is custom shaped.
50 | */
51 | getItemValue: PropTypes.func,
52 | /**
53 | * Is the item selected
54 | */
55 | isSelected: PropTypes.bool,
56 | /**
57 | * Is the item disabled
58 | */
59 | disabled: PropTypes.bool,
60 | /**
61 | * Render custom item
62 | */
63 | renderItem: PropTypes.func,
64 | /**
65 | * Callback for onPress action
66 | */
67 | onPress: PropTypes.func,
68 | /**
69 | * Callback for onLayout event
70 | */
71 | onSelectedLayout: PropTypes.func,
72 | };
73 |
74 | constructor(props) {
75 | super(props);
76 |
77 | this.onSelectedLayout = this.onSelectedLayout.bind(this);
78 | }
79 |
80 | generateStyles() {
81 | this.styles = createStyles(this.props);
82 | }
83 |
84 | getLabel() {
85 | const { value, label } = this.props;
86 | if (_.isObject(value)) {
87 | return (
88 | _.invoke(this.props, 'getItemLabel', value) || _.get(value, 'label')
89 | );
90 | }
91 | return label;
92 | }
93 |
94 | renderSelectedIndicator() {
95 | const { isSelected, disabled } = this.props;
96 | if (isSelected) {
97 | return (
98 |
105 | );
106 | }
107 | }
108 |
109 | renderItem() {
110 | const { disabled } = this.props;
111 | return (
112 |
113 |
120 | {this.getLabel()}
121 |
122 | {this.renderSelectedIndicator()}
123 |
124 | );
125 | }
126 |
127 | onSelectedLayout(...args) {
128 | this.props.onSelectedLayout && this.props.onSelectedLayout(...args);
129 | }
130 |
131 | render() {
132 | const {
133 | renderItem,
134 | label,
135 | value,
136 | disabled,
137 | onPress,
138 | isSelected,
139 | testID,
140 | } = this.props;
141 |
142 | return (
143 | onPress(_.isObject(value) ? value : { value, label })}
147 | onLayout={isSelected ? this.onSelectedLayout : undefined}
148 | disabled={disabled}
149 | testID={testID}
150 | >
151 | {renderItem ? renderItem(value, this.props) : this.renderItem()}
152 |
153 | );
154 | }
155 | }
156 |
157 | function createStyles({ rtl }) {
158 | return StyleSheet.create({
159 | container: {
160 | height: 56.5,
161 | paddingHorizontal: 23,
162 | borderColor: Colors.rgba(Colors.dark10, 0.1),
163 | borderBottomWidth: 1,
164 | flexDirection: rtl ? 'row-reverse' : 'row',
165 | },
166 | labelText: {
167 | ...Typography.text70,
168 | color: Colors.dark10,
169 | flex: 1,
170 | textAlign: rtl ? 'right' : 'left',
171 | },
172 | labelTextDisabled: {
173 | color: Colors.dark60,
174 | },
175 | checkIcon: {
176 | tintColor: ThemeManager.primaryColor,
177 | },
178 | checkIconDisabled: {
179 | tintColor: Colors.dark60,
180 | },
181 | });
182 | }
183 |
184 | module.exports = PickerItem;
185 |
--------------------------------------------------------------------------------
/src/components/picker/PickerPresenter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 |
11 | export function isItemSelected(childValue, selectedValue) {
12 | let isSelected = false;
13 |
14 | if (Array.isArray(selectedValue)) {
15 | isSelected = _.includes(selectedValue, childValue);
16 | } else {
17 | isSelected = childValue === selectedValue;
18 | }
19 | return isSelected;
20 | }
21 |
22 | export function getItemValue(props) {
23 | if (_.isArray(props.value)) {
24 | return props.getItemValue
25 | ? _.map(props.value, item => props.getItemValue(item))
26 | : _.map(props.value, 'value');
27 | } else if (!_.isObject(props.value)) {
28 | return props.value;
29 | }
30 | return (
31 | _.invoke(props, 'getItemValue', props.value) || _.get(props.value, 'value')
32 | );
33 | }
34 |
35 | export function getItemLabel(props) {
36 | return (
37 | _.invoke(props, 'getLabel', props.value) || _.get(props.value, 'label')
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/picker/__test__/PickerPresenter.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const uut = require('../PickerPresenter');
10 |
11 | describe('components/PickerPresenter', () => {
12 | it('should isItemSelected, handle single mode', () => {
13 | expect(uut.isItemSelected('value', 'value')).toBe(true);
14 | expect(uut.isItemSelected('value', 'value2')).toBe(false);
15 | });
16 |
17 | it('should isItemSelected, handle multi mode', () => {
18 | expect(uut.isItemSelected('value', ['value', 'value1', 'value3'])).toBe(
19 | true,
20 | );
21 | expect(uut.isItemSelected('value', ['value1', 'value2', 'value3'])).toBe(
22 | false,
23 | );
24 | expect(uut.isItemSelected('value', [])).toBe(false);
25 | expect(uut.isItemSelected('value', undefined)).toBe(false);
26 | });
27 |
28 | describe('getItemValue', () => {
29 | it('should return item value when item has value prop', () => {
30 | expect(uut.getItemValue({ value: { value: 'item value' } })).toBe(
31 | 'item value',
32 | );
33 | });
34 |
35 | it('should return item value for multiple values', () => {
36 | const itemProps = {
37 | value: [{ value: '1' }, { value: '2' }, { value: '3' }],
38 | };
39 | expect(uut.getItemValue(itemProps)).toEqual(['1', '2', '3']);
40 | });
41 |
42 | it('should return item value when item has getItemValue prop', () => {
43 | const itemProps = {
44 | value: { name: 'value', age: 12 },
45 | getItemValue: item => item.name,
46 | };
47 | expect(uut.getItemValue(itemProps)).toBe('value');
48 | });
49 |
50 | it('should return item value for multiple values when item has getItemValue prop', () => {
51 | const itemProps = {
52 | value: [{ name: 'david' }, { name: 'sarah' }, { name: 'jack' }],
53 | getItemValue: item => item.name,
54 | };
55 | expect(uut.getItemValue(itemProps)).toEqual(['david', 'sarah', 'jack']);
56 | });
57 |
58 | it('should support backward compatibility for when child item value was not an object', () => {
59 | const itemProps = { value: 'item-value' };
60 | expect(uut.getItemValue(itemProps)).toEqual('item-value');
61 | });
62 | });
63 |
64 | describe('getItemLabel', () => {
65 | it('should return item label when value is an object', () => {
66 | const itemProps = { value: { value: 'value', label: 'label' } };
67 | expect(uut.getItemLabel(itemProps)).toEqual('label');
68 | });
69 |
70 | it('should return item label according to getLabel function ', () => {
71 | const getLabel = itemValue => `${itemValue.value} - ${itemValue.label}`;
72 | const itemProps = { value: { value: 'value', label: 'label' }, getLabel };
73 | expect(uut.getItemLabel(itemProps)).toEqual('value - label');
74 | });
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/src/components/picker/__test__/index.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const Picker = require('../index');
10 |
11 | const countries = [
12 | { label: 'Israel', value: 'IL' },
13 | { label: 'United States', value: 'US' },
14 | { label: 'Germany', value: 'DE' },
15 | { label: 'Italy', value: 'IT' },
16 | { label: 'Spain', value: 'ES ' },
17 | ];
18 |
19 | describe('Picker', () => {
20 | describe('getLabel', () => {
21 | it('should get label of a simple item', () => {
22 | let uut = new Picker({ value: countries[2] });
23 | expect(uut.getLabel()).toEqual(countries[2].label);
24 | uut = new Picker({ value: countries[3] });
25 | expect(uut.getLabel()).toEqual(countries[3].label);
26 | });
27 |
28 | it('should get label out of an array of items', () => {
29 | const uut = new Picker({ value: [countries[2], countries[4]] });
30 | expect(uut.getLabel()).toEqual(
31 | `${countries[2].label}, ${countries[4].label}`,
32 | );
33 | });
34 | });
35 |
36 | describe('handlePickerOnPress', () => {
37 | it('should get label out of an array of items', () => {
38 | const onPress = jest.fn(() => {});
39 | const uut = new Picker({ value: countries[0], onPress });
40 | uut.toggleExpandableModal = jest.fn(uut.toggleExpandableModal);
41 |
42 | uut.handlePickerOnPress();
43 | expect(onPress).toHaveBeenCalled();
44 | expect(uut.toggleExpandableModal).toHaveBeenCalled();
45 | });
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/src/components/touchables/Touchable.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const React = require('react');
10 | const {
11 | Platform,
12 | TouchableHighlight,
13 | TouchableNativeFeedback,
14 | } = require('react-native');
15 |
16 | function RNCTouchableIOS(props: Object): ReactElement {
17 | return (
18 |
23 | );
24 | }
25 |
26 | const RNCTouchable =
27 | Platform.OS === 'android' ? TouchableNativeFeedback : RNCTouchableIOS;
28 |
29 | module.exports = RNCTouchable;
30 |
--------------------------------------------------------------------------------
/src/components/touchables/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | import Touchable from './Touchable';
10 |
11 | export { Touchable };
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | const CustomComponents = require('react-native-deprecated-custom-components');
8 | const KeyboardAware = require('react-native-keyboard-aware-scrollview');
9 | const RNUILib = require('react-native-ui-lib');
10 | const components = require('./components');
11 |
12 | module.exports = {
13 | ...CustomComponents,
14 | ...KeyboardAware,
15 | ...RNUILib,
16 | ...components,
17 | };
18 |
--------------------------------------------------------------------------------
/src/style/BorderRadiuses.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 |
11 | const { Constants } = require('../helpers');
12 |
13 | class BorderRadiuses {
14 | br0 = 0;
15 | br10 = Constants.isIOS ? 3 : 2;
16 | br20 = 6;
17 | br30 = Constants.isIOS ? 9 : 8;
18 | br40 = 12;
19 | br50 = Constants.isIOS ? 15 : 16;
20 | br60 = 20;
21 | br100 = 999;
22 |
23 | loadBorders(borders) {
24 | _.forEach(borders, (value, key) => {
25 | this[key] = value;
26 | });
27 | }
28 |
29 | getKeysPattern() {
30 | return new RegExp(
31 | _.chain(this)
32 | .keys()
33 | .map(key => [`${key}`])
34 | .flatten()
35 | .join('|')
36 | .value(),
37 | );
38 | }
39 | }
40 |
41 | module.exports = new BorderRadiuses();
42 |
--------------------------------------------------------------------------------
/src/style/Colors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const { colorsPalette } = require('./ColorsPalette');
11 |
12 | class Colors {
13 | /**
14 | * Load custom set of colors
15 | * arguments:
16 | * colors - map of keys and colors values e.g {dark10: '#20303C', dark20: '#43515C'}
17 | */
18 | loadColors(colors) {
19 | _.forEach(colors, (value, key) => {
20 | this[key] = value;
21 | });
22 | }
23 |
24 | /**
25 | * Add alpha to hex or rgb color
26 | * arguments:
27 | * p1 - hex color / R part of RGB
28 | * p2 - opacity / G part of RGB
29 | * p3 - B part of RGB
30 | * p4 - opacity
31 | */
32 | rgba(p1, p2, p3, p4) {
33 | let hex;
34 | let opacity;
35 | let red;
36 | let green;
37 | let blue;
38 |
39 | if (arguments.length === 2) {
40 | hex = p1;
41 | opacity = p2;
42 |
43 | hex = validateHex(hex);
44 | red = parseInt(hex.substring(0, 2), 16);
45 | green = parseInt(hex.substring(2, 4), 16);
46 | blue = parseInt(hex.substring(4, 6), 16);
47 | } else if (arguments.length === 4) {
48 | red = validateRGB(p1);
49 | green = validateRGB(p2);
50 | blue = validateRGB(p3);
51 | opacity = p4;
52 | } else {
53 | throw new Error('rgba can work with either 2 or 4 arguments');
54 | }
55 |
56 | return `rgba(${red}, ${green}, ${blue}, ${opacity})`;
57 | }
58 |
59 | getBackgroundKeysPattern() {
60 | return new RegExp(
61 | _.chain(this)
62 | .keys()
63 | .map(key => [`bg-${key}`, `background-${key}`])
64 | .flatten()
65 | .join('|')
66 | .value(),
67 | );
68 | }
69 | }
70 |
71 | function validateRGB(value) {
72 | if (isNaN(value) || value > 255 || value < 0) {
73 | throw new Error(
74 | `${value} is invalid rgb code, please use number between 0-255`,
75 | );
76 | }
77 |
78 | return value;
79 | }
80 |
81 | function validateHex(value) {
82 | if (!/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value)) {
83 | throw new Error(`${value} is invalid hex color`);
84 | }
85 |
86 | return value.replace('#', '');
87 | }
88 |
89 | const colorObject = new Colors();
90 | colorObject.loadColors(colorsPalette);
91 |
92 | module.exports = colorObject;
93 |
--------------------------------------------------------------------------------
/src/style/ColorsPalette.js:
--------------------------------------------------------------------------------
1 | const colorsPalette = {
2 | dark10: '#20303C',
3 | dark20: '#43515C',
4 | dark30: '#66737C',
5 | dark40: '#858F96',
6 | dark50: '#A3ABB0',
7 | dark60: '#C2C7CB',
8 | dark70: '#E0E3E5',
9 | dark80: '#F2F4F5',
10 | // BLUE,
11 | blue10: '#3182C8',
12 | blue20: '#4196E0',
13 | blue30: '#459FED',
14 | blue40: '#57a8ef',
15 | blue50: '#8fc5f4',
16 | blue60: '#b5d9f8',
17 | blue70: '#daecfb',
18 | blue80: '#ecf5fd',
19 |
20 | // CYAN,
21 | cyan10: '#00AAAF',
22 | cyan20: '#32BABC',
23 | cyan30: '#3CC7C5',
24 | cyan40: '#64D4D2',
25 | cyan50: '#8BDFDD',
26 | cyan60: '#B1E9E9',
27 | cyan70: '#D8F4F4',
28 | cyan80: '#EBF9F9',
29 | // GREEN,
30 | green10: '#00A65F',
31 | green20: '#32B76C',
32 | green30: '#65C888',
33 | green40: '#84D3A0',
34 | green50: '#A3DEB8',
35 | green60: '#C1E9CF',
36 | green70: '#E8F7EF',
37 | green80: '#F3FBF7',
38 | // YELLOW,
39 | yellow10: '#E2902B',
40 | yellow20: '#FAA030',
41 | yellow30: '#FAAD4D',
42 | yellow40: '#FBBD71',
43 | yellow50: '#FCCE94',
44 | yellow60: '#FDDEB8',
45 | yellow70: '#FEEFDB',
46 | yellow80: '#FEF7ED',
47 | // ORANGE,
48 | orange10: '#D9644A',
49 | orange20: '#E66A4E',
50 | orange30: '#F27052',
51 | orange40: '#F37E63',
52 | orange50: '#F7A997',
53 | orange60: '#FAC6BA',
54 | orange70: '#FCE2DC',
55 | orange80: '#FEF0ED',
56 | // RED,
57 | red10: '#CF262F',
58 | red20: '#EE2C38',
59 | red30: '#F2564D',
60 | red40: '#F57871',
61 | red50: '#F79A94',
62 | red60: '#FABBB8',
63 | red70: '#FCDDDB',
64 | red80: '#FEEEED',
65 | // PURPLE,
66 | purple10: '#8B1079',
67 | purple20: '#A0138E',
68 | purple30: '#B13DAC',
69 | purple40: '#C164BD',
70 | purple50: '#D08BCD',
71 | purple60: '#E0B1DE',
72 | purple70: '#EFD8EE',
73 | purple80: '#F7EBF7',
74 | // VIOLET,
75 | violet10: '#48217B',
76 | violet20: '#542790',
77 | violet30: '#733CA6',
78 | violet40: '#8F63B8',
79 | violet50: '#AB8ACA',
80 | violet60: '#C7B1DB',
81 | violet70: '#E3D8ED',
82 | violet80: '#F1EBF6',
83 | // WHITE,
84 | white: '#ffffff',
85 | black: '#000000',
86 | };
87 |
88 | // For Eslint --fix
89 | const extraFixColorsMap = {
90 | black: 'black',
91 | white: 'white',
92 | '#000': 'black',
93 | '#fff': 'white',
94 | };
95 |
96 | module.exports = {
97 | colorsPalette,
98 | extraFixColorsMap,
99 | };
100 |
--------------------------------------------------------------------------------
/src/style/Shadows.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const Colors = require('./Colors');
11 |
12 | const Shadows = {
13 | white10: {
14 | top: {
15 | shadowColor: Colors.dark20,
16 | shadowOpacity: 0.04,
17 | shadowRadius: 13.5,
18 | },
19 | bottom: {
20 | shadowColor: Colors.dark10,
21 | shadowOpacity: 0.09,
22 | shadowRadius: 2,
23 | shadowOffset: { height: 2, width: 0 },
24 | },
25 | },
26 | white20: {
27 | top: { shadowColor: Colors.dark20, shadowOpacity: 0.06, shadowRadius: 15 },
28 | bottom: {
29 | shadowColor: Colors.dark10,
30 | shadowOpacity: 0.04,
31 | shadowRadius: 3,
32 | shadowOffset: { height: 3, width: 0 },
33 | },
34 | },
35 | white30: {
36 | top: { shadowColor: Colors.dark20, shadowOpacity: 0.05, shadowRadius: 12 },
37 | bottom: {
38 | shadowColor: Colors.dark10,
39 | shadowOpacity: 0.06,
40 | shadowRadius: 4.5,
41 | shadowOffset: { height: 4, width: 0 },
42 | },
43 | },
44 | white40: {
45 | top: {
46 | shadowColor: Colors.dark20,
47 | shadowOpacity: 0.06,
48 | shadowRadius: 18.5,
49 | },
50 | bottom: {
51 | shadowColor: Colors.dark10,
52 | shadowOpacity: 0.07,
53 | shadowRadius: 8.5,
54 | shadowOffset: { height: 5, width: 0 },
55 | },
56 | },
57 | dark10: {
58 | top: {
59 | shadowColor: Colors.dark20,
60 | shadowOpacity: 0.02,
61 | shadowRadius: 13.5,
62 | },
63 | bottom: {
64 | shadowColor: Colors.dark10,
65 | shadowOpacity: 0.03,
66 | shadowRadius: 2,
67 | shadowOffset: { height: 2, width: 0 },
68 | },
69 | },
70 | dark20: {
71 | top: { shadowColor: Colors.dark20, shadowOpacity: 0.03, shadowRadius: 15 },
72 | bottom: {
73 | shadowColor: Colors.dark10,
74 | shadowOpacity: 0.02,
75 | shadowRadius: 3,
76 | shadowOffset: { height: 2.5, width: 0 },
77 | },
78 | },
79 | dark30: {
80 | top: {
81 | shadowColor: Colors.dark10,
82 | shadowOpacity: 0.04,
83 | shadowRadius: 3.5,
84 | shadowOffset: { height: 3, width: 0 },
85 | },
86 | bottom: {
87 | shadowColor: Colors.dark20,
88 | shadowOpacity: 0.04,
89 | shadowRadius: 8,
90 | shadowOffset: { height: 7, width: 0 },
91 | },
92 | },
93 | dark40: {
94 | top: {
95 | shadowColor: Colors.dark10,
96 | shadowOpacity: 0.04,
97 | shadowRadius: 4.5,
98 | shadowOffset: { height: 5, width: 0 },
99 | },
100 | bottom: {
101 | shadowColor: Colors.dark20,
102 | shadowOpacity: 0.04,
103 | shadowRadius: 9,
104 | shadowOffset: { height: 10, width: 0 },
105 | },
106 | },
107 |
108 | /**
109 | * Load custom set of shadows
110 | * arguments:
111 | * shadows - map of keys and values
112 | * e.g
113 | * dark40: {
114 | * top: {shadowColor: Colors.dark10, shadowOpacity: 0.04, shadowRadius: 4.5, shadowOffset: {height: 5, width: 0}},
115 | * bottom: {shadowColor: Colors.dark20, shadowOpacity: 0.04, shadowRadius: 9, shadowOffset: {height: 10, width: 0}},
116 | * }
117 | */
118 | loadShadows(shadows) {
119 | _.forEach(shadows, (value, key) => {
120 | this[key] = value;
121 | });
122 | },
123 | };
124 |
125 | module.exports = Shadows;
126 |
--------------------------------------------------------------------------------
/src/style/Spacings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const { Constants } = require('../helpers');
11 |
12 | class Spacings {
13 | s1 = Constants.isIOS ? 3 : 4;
14 | s2 = Constants.isIOS ? 6 : 8;
15 | s3 = Constants.isIOS ? 9 : 12;
16 | s4 = Constants.isIOS ? 12 : 16;
17 | s5 = Constants.isIOS ? 15 : 20;
18 | s6 = Constants.isIOS ? 18 : 24;
19 | s7 = Constants.isIOS ? 21 : 28;
20 | s8 = Constants.isIOS ? 24 : 32;
21 | s9 = Constants.isIOS ? 27 : 36;
22 | s10 = Constants.isIOS ? 30 : 40;
23 |
24 | loadSpacings(spacings) {
25 | _.forEach(spacings, (value, key) => {
26 | this[key] = value;
27 | });
28 | }
29 |
30 | getKeysPattern() {
31 | return new RegExp(
32 | _.chain(this)
33 | .keys()
34 | .join('|')
35 | .value(),
36 | );
37 | }
38 | }
39 |
40 | module.exports = new Spacings();
41 |
--------------------------------------------------------------------------------
/src/style/ThemeManager.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const Colors = require('./Colors');
11 |
12 | class ThemeManager {
13 | theme = {
14 | primaryColor: Colors.blue30,
15 | CTA: {
16 | textColor: Colors.white,
17 | disabledColor: Colors.dark60,
18 | backgroundColor: Colors.blue30,
19 | },
20 | titleColor: Colors.dark10,
21 | subtitleColor: Colors.dark40,
22 | dividerColor: Colors.dark70,
23 | components: {
24 | TouchableOpacity: {
25 | throttleTime: 0,
26 | throttleOptions: { leading: true, trailing: false },
27 | },
28 | },
29 | };
30 |
31 | setTheme(overrides) {
32 | this.theme = _.merge(this.theme, overrides);
33 | }
34 |
35 | getTheme() {
36 | return this.theme;
37 | }
38 |
39 | setItem(key, value) {
40 | if (key === 'components')
41 | throw new Error('Overriding the "components" key is not possible.');
42 | this.theme[key] = value;
43 | }
44 |
45 | getItem(key) {
46 | return this.theme[key];
47 | }
48 |
49 | setComponentTheme(componentName, overrides) {
50 | if (_.isFunction(overrides)) {
51 | this.theme.components[componentName] = overrides;
52 | } else {
53 | this.theme.components[componentName] = _.cloneDeep(overrides);
54 | }
55 | }
56 |
57 | get components() {
58 | return this.theme.components;
59 | }
60 |
61 | get primaryColor() {
62 | return this.theme.primaryColor;
63 | }
64 |
65 | get CTATextColor() {
66 | return this.theme.CTA.textColor;
67 | }
68 |
69 | get CTADisabledColor() {
70 | return this.theme.CTA.disabledColor;
71 | }
72 |
73 | get CTABackgroundColor() {
74 | return this.theme.CTA.backgroundColor;
75 | }
76 |
77 | get titleColor() {
78 | return this.theme.titleColor;
79 | }
80 |
81 | get subtitleColor() {
82 | return this.theme.subtitleColor;
83 | }
84 |
85 | get dividerColor() {
86 | return this.theme.dividerColor;
87 | }
88 | }
89 |
90 | module.exports = new ThemeManager();
91 |
--------------------------------------------------------------------------------
/src/style/Typography.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani)
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | const _ = require('lodash');
10 | const { Constants } = require('../helpers');
11 |
12 | class Typography {
13 | text10 = {
14 | fontSize: 64,
15 | fontWeight: '100',
16 | lineHeight: Math.floor(64 * 1.4),
17 | fontFamily: Constants.isAndroid ? 'sans-serif-thin' : undefined,
18 | };
19 | text20 = {
20 | fontSize: 50,
21 | fontWeight: '100',
22 | lineHeight: Math.floor(50 * 1.4),
23 | fontFamily: Constants.isAndroid ? 'sans-serif-thin' : undefined,
24 | };
25 | text30 = {
26 | fontSize: 36,
27 | fontWeight: Constants.isAndroid ? '100' : '200',
28 | lineHeight: Math.floor(36 * 1.3),
29 | fontFamily: Constants.isAndroid ? 'sans-serif-thin' : undefined,
30 | };
31 | text40 = {
32 | fontSize: 28,
33 | fontWeight: '300',
34 | lineHeight: Constants.isAndroid
35 | ? Math.floor(28 * 1.4)
36 | : Math.floor(28 * 1.21),
37 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
38 | };
39 | text50 = {
40 | fontSize: Constants.isAndroid ? 24 : 22,
41 | fontWeight: '300',
42 | lineHeight: Constants.isAndroid
43 | ? Math.floor(24 * 1.17)
44 | : Math.floor(22 * 1.27),
45 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
46 | };
47 | text60 = {
48 | fontSize: 20,
49 | fontWeight: '300',
50 | lineHeight: Math.floor(20 * 1.2),
51 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
52 | };
53 | text70 = {
54 | fontSize: Constants.isAndroid ? 16 : 17,
55 | fontWeight: '300',
56 | lineHeight: Constants.isAndroid
57 | ? Math.floor(16 * 1.38)
58 | : Math.floor(17 * 1.29),
59 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
60 | };
61 | text80 = {
62 | fontSize: Constants.isAndroid ? 14 : 15,
63 | fontWeight: '300',
64 | lineHeight: Constants.isAndroid
65 | ? Math.floor(14 * 1.33)
66 | : Math.floor(15 * 1.33),
67 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
68 | };
69 | text90 = {
70 | fontSize: Constants.isAndroid ? 12 : 13,
71 | fontWeight: '300',
72 | lineHeight: Constants.isAndroid
73 | ? Math.floor(12 * 1.33)
74 | : Math.floor(13 * 1.38),
75 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
76 | };
77 | text100 = {
78 | fontSize: Constants.isAndroid ? 10 : 11,
79 | fontWeight: '300',
80 | lineHeight: Constants.isAndroid
81 | ? Math.floor(10 * 1.18)
82 | : Math.floor(11 * 1.18),
83 | fontFamily: Constants.isAndroid ? 'sans-serif-light' : undefined,
84 | };
85 |
86 | /**
87 | * Load custom set of typographies
88 | * arguments:
89 | * typographies - map of keys and typography values
90 | * e.g {text15: {fontSize: 58, fontWeight: '100', lineHeight: Math.floor(58 * 1.4)}}
91 | */
92 | loadTypographies(typographies) {
93 | _.forEach(typographies, (value, key) => {
94 | this[key] = value;
95 | });
96 | }
97 |
98 | getKeysPattern() {
99 | return new RegExp(
100 | _.chain(this)
101 | .keys()
102 | .map(key => [`${key}`])
103 | .flatten()
104 | .join('|')
105 | .value(),
106 | );
107 | }
108 | }
109 |
110 | module.exports = new Typography();
111 |
--------------------------------------------------------------------------------
/src/style/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Reza (github.com/rghorbani).
3 | *
4 | * @flow
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = {
10 | get BorderRadiuses() {
11 | return require('./BorderRadiuses');
12 | },
13 | get Colors() {
14 | return require('./Colors');
15 | },
16 | get Shadows() {
17 | return require('./Shadows');
18 | },
19 | get Spacings() {
20 | return require('./Spacings');
21 | },
22 | get ThemeManager() {
23 | return require('./ThemeManager');
24 | },
25 | get Typography() {
26 | return require('./Typography');
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | "target":
5 | "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
6 | "module":
7 | "es2015" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
8 | // "lib": [], /* Specify library files to be included in the compilation. */
9 | // "allowJs": true, /* Allow javascript files to be compiled. */
10 | // "checkJs": true, /* Report errors in .js files. */
11 | "jsx": "react-native" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
12 | "declaration": true /* Generates corresponding '.d.ts' file. */,
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | // "outFile": "./", /* Concatenate and emit output to single file. */
15 | "outDir": "./typings" /* Redirect output structure to the directory. */,
16 | "rootDir":
17 | "./dist-ts" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
18 | // "removeComments": true, /* Do not emit comments to output. */
19 | // "noEmit": true, /* Do not emit outputs. */
20 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
21 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
22 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
23 |
24 | /* Strict Type-Checking Options */
25 | "strict": false /* Enable all strict type-checking options. */,
26 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
27 | "skipLibCheck": true,
28 | // "strictNullChecks": true, /* Enable strict null checks. */
29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
31 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
32 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
33 |
34 | /* Additional Checks */
35 | // "noUnusedLocals": true, /* Report errors on unused locals. */
36 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
37 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
38 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
39 |
40 | /* Module Resolution Options */
41 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
42 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
43 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
44 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
45 | // "typeRoots": [], /* List of folders to include type definitions from. */
46 | "types": [
47 | // "jest",
48 | // "lodash",
49 | "prop-types",
50 | "react",
51 | "react-native"
52 | ], /* Type declaration files to be included in compilation. */
53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
54 | // "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
56 |
57 | /* Source Map Options */
58 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
59 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
60 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
61 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
62 |
63 | /* Experimental Options */
64 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
65 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
66 | },
67 | "include": [
68 | // "./src/**/*"
69 | "./dist-ts/**/*"
70 | ]
71 | }
72 |
--------------------------------------------------------------------------------