Purescript bindings for react-native
- Latest react-native version tested against 0.51
- Movie example project
bower install purescript-reactnative --save
- CHANGELOG
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
EffectFnX
to 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.
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 are defined using arrays of StyleProp
s 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
]
}
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} }
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
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.
- Jolse Maginnis (
[email protected] @doolse2
) - Jens Krause (
@sectore
) - Nicholas Brady (
[email protected]
) - Don Abrams (
[email protected]
) - Ben Fleisch (
[email protected]
) - Alexander Obi (
[email protected]
)