Package

purescript-reactnative

Repository
doolse/purescript-reactnative
License
MIT
Uploaded by
doolse

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:

  • Keep up to date with purescript language 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 EffFnX to model the event callbacks. There will be additional libraries for your favourite action library - e.g. purescript-reactnative-thermite I have also made a very small and simple library for dispatching react actions purescript-dispatcher-react.

Examples and Naming conventions

All component functions follow the naming convention of:

  • image - The most common properties
  • image_ - Only mandatory properties
  • image' - 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 --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 Control.Monad.Eff (Eff)
import React (ReactClass, Render, createClass, getProps, spec)
import ReactNative.API (REGISTER, registerComponent)
import ReactNative.Components.Text (text_)

render :: forall props state eff. Render props state eff
render ctx = do
            _ <- getProps ctx  -- get props from context if needed
            pure(text_ "Hello World")

app :: forall p. ReactClass p
app = createClass $ spec {} render

main :: forall e. Eff (register:: REGISTER | e) 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]
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)