Home

Awesome

purescript-reactnative

Latest release Travis Build

Purescript bindings for react-native

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:

Examples and Naming conventions

All component functions follow the naming convention of:

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:

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 --force

Install 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:

ComponentSupported
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-
APIVersion
alert[x]
color[x]
ListViewDataSource[x]

Anything marked with * may not have 100% coverage of API calls yet.

Contributors