Purescript bindings for react-native
- Latest react-native version tested against 0.51
- Movie example project
bower install purescript-reactnative --save- CHANGELOG
Goals
React-native is a fast moving javascript project which is frequently released (monthly at the time of writing). Much too fast for me to realistically keep all the purescript bindings continually up-to-date, so the goals are:
-
Keep up to date with
purescriptlanguage releases. -
Keep the official React Native docs as the best place to go for help. This will be acheived by:
-
Using record types for property passing.
-
Use
newtype | foreign import data+ smart constructors for property types. -
Have unsafe versions of all the component functions, so if the library is lagging behind or the component does not yet have a safe version, it's still possible to use the library without too much hassle.
-
Stay event framework agnostic. This is acheived by using
EffectFnXto model the event callbacks. I have also made a very small and simple library for working with react event handling (based on ReaderT) purescript-dispatcher-react.
Examples and Naming conventions
All component functions follow the naming convention of:
image- The most common propertiesimage_- Only mandatory propertiesimage'- Mandatory properties and all optional properties - uses purescript row constraints to allow a single record to be passed in.imageU- Unsafe, takes any properties
Enum property types will either be accessible through functions with the name of the enum:
newtype FlexDirection = FlexDirection String row :: FlexDirection row = FlexDirection "row" rowReverse :: FlexDirection rowReverse = FlexDirection "row-reverse" column :: FlexDirection column = FlexDirection "column" columnReverse :: FlexDirection columnReverse = FlexDirection "column-reverse"`
or a record which has a field for each value in the enum:
newtype KeyboardDismissMode = KeyboardDismissMode String keyboardDismissMode :: { none :: KeyboardDismissMode , interactive :: KeyboardDismissMode , onDrag :: KeyboardDismissMode } keyboardDismissMode = { none: KeyboardDismissMode "none" , interactive: KeyboardDismissMode "interactive" , onDrag: KeyboardDismissMode "on-drag" }
If you want to examples check out the code in the purescript-reactnative port of the Movies example
app which comes with the react-native source code.
https://github.com/doolse/purescript-reactnative-example
Styles
Styles are defined using arrays of StyleProps and you can create a stylesheet simply by creating a record which contains these styles defined with staticStyles:
sheet :: { searchBar :: Styles , searchBarInput :: Styles , spinner :: Styles , icon :: Styles } sheet = { searchBar: staticStyles [ flexDirection row, alignItems center, backgroundColor $ rgbi 0xa9a9a9, height 56 ], searchBarInput: staticStyles [ flex 1, fontSize 20, fontWeight bold, color white, height 50, padding 0, backgroundColor transparent ], spinner: staticStyles [ width 30, height 30, marginRight 16 ], icon: staticStyles [ width 24, height 24, marginHorizontal 8 ] }
Platform specific code
The decision to not do anything special with the type system concerning platform specific components is because:
- a) Usually it very obvious from the component name
- b) It would be a significant amount of extra work and type signature noise and I don't think the benefits justify it.
Having said that, platform specific properties have been separated into sub properties for clarity. For example:
type ViewProps eff = { style :: Styles -- More platform neutral properties , ios :: { shouldRasterizeIOS :: Boolean }, , android :: { needsOffscreenAlphaCompositing :: Boolean } }
import ReactNative.Components (iosProps,androidProps) main = view' {accessible:true, android:androidProps {collapsable:true}, ios:iosProps {shouldRasterizeIOS:true} }
Getting started - Hello World
This is a barebones starter "in accordance with the ancient traditions of our people" meant to parallel the example on facebook's react-native docs.
Firstly, install the react native cli if you don't have it already, and then start a barebones react-native project:
npm install -g react-native-cli react-native init HelloWorld
Also add in the basic purescript project structure to the project.
cd HelloWorld
pulp init --forceInstall purescript react native dependency:
bower install purescript-reactnative --save
Replace the contents of src/Main.purs with
module Main where import Prelude import Effect (Effect) import React (ReactClass, statelessComponent) import ReactNative.API (registerComponent) import ReactNative.Components.Text (text_) app :: forall p. ReactClass {|p} app = statelessComponent render where render _ = text_ "Hello World" main :: Effect Unit main = do registerComponent "HelloWorld" app
Then from your project root, build the purescript project and output it to index.js
pulp build --to index.js
And that's it! Fire up an emulator (e.g. android avd) or connect a device and launch your app:
react-native run-android
Component support table
The plan is to initially support a subset of the components fully, and provide unsafe functions for many of the others. Type safe versions of the components are created based off the react-native documentation, this table shows the current status:
| Component | Supported |
|---|---|
View |
[x] |
SafeAreaView |
[x] |
Text |
[x] |
TextInput |
[x] |
Switch |
[x] |
Touchable* |
[x] |
Picker |
[x] |
Slider |
[x] |
ActivityIndicator |
[x] |
ListView |
[x] |
ScrollView |
[x] |
Image |
[x] |
RefreshControl |
[x] |
Button |
[x] |
NavigatorIOS |
[x] * |
DrawerLayoutAndroid |
[x] |
ToolbarAndroid |
[x] |
Modal |
[x] |
ProgressBarAndroid |
[x] |
DatePickerIOS |
- |
KeyboardAvoidingView |
- |
MapView |
- |
ProgressViewIOS |
- |
SegmentedControlIOS |
- |
StatusBar |
- |
SnapshotViewIOS |
- |
TabBarIOS |
- |
TabBarIOSItem |
- |
ViewPagerAndroid |
- |
WebView |
- |
| API | Version |
|---|---|
alert |
[x] |
color |
[x] |
ListViewDataSource |
[x] |
Anything marked with * may not have 100% coverage of API calls yet.
Contributors
- Jolse Maginnis (
doolse@gmail.com @doolse2) - Jens Krause (
@sectore) - Nicholas Brady (
nick.brady@smartrac-group.com) - Don Abrams (
don.abrams@smartrac-group.com) - Ben Fleisch (
bfly2000@gmail.com) - Alexander Obi (
alexander.obi@smartrac-group.com)