diff --git a/bower.json b/bower.json
index 5847ab0..112c983 100644
--- a/bower.json
+++ b/bower.json
@@ -9,6 +9,9 @@
"dependencies": {
"purescript-functions": "^3.0.0",
"purescript-eff": "^3.1.0",
- "purescript-unsafe-coerce": "^3.0.0"
+ "purescript-unsafe-coerce": "^3.0.0",
+ "purescript-nullable": "^3.0.0",
+ "purescript-typelevel-prelude": "^2.6.0",
+ "purescript-record": "^0.2.6"
}
}
diff --git a/examples/controlled-input/.gitignore b/examples/controlled-input/.gitignore
new file mode 100644
index 0000000..645684d
--- /dev/null
+++ b/examples/controlled-input/.gitignore
@@ -0,0 +1,4 @@
+output
+html/index.js
+package-lock.json
+node_modules
diff --git a/examples/controlled-input/Makefile b/examples/controlled-input/Makefile
new file mode 100644
index 0000000..f266443
--- /dev/null
+++ b/examples/controlled-input/Makefile
@@ -0,0 +1,5 @@
+all:
+ purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
+ purs bundle --module ControlledInput output/*/*.js > output/bundle.js
+ echo 'module.exports = PS.ControlledInput;' >> output/bundle.js
+ node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js
diff --git a/examples/controlled-input/README.md b/examples/controlled-input/README.md
new file mode 100644
index 0000000..2004b87
--- /dev/null
+++ b/examples/controlled-input/README.md
@@ -0,0 +1,12 @@
+# Controlled Input Example
+
+## Building
+
+```
+npm install
+make all
+```
+
+This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle.
+
+Then open `html/index.html` in your browser.
diff --git a/examples/controlled-input/html/index.html b/examples/controlled-input/html/index.html
new file mode 100644
index 0000000..6b93b7c
--- /dev/null
+++ b/examples/controlled-input/html/index.html
@@ -0,0 +1,10 @@
+
+
+
+ react-basic example
+
+
+
+
+
+
diff --git a/examples/controlled-input/index.js b/examples/controlled-input/index.js
new file mode 100644
index 0000000..cbf31c0
--- /dev/null
+++ b/examples/controlled-input/index.js
@@ -0,0 +1,10 @@
+"use strict";
+
+var React = require("react");
+var ReactDOM = require("react-dom");
+var ControlledInput = require("./output/bundle.js");
+
+ReactDOM.render(
+ React.createElement(ControlledInput.component),
+ document.getElementById("container")
+);
diff --git a/examples/controlled-input/package.json b/examples/controlled-input/package.json
new file mode 100644
index 0000000..0750eb8
--- /dev/null
+++ b/examples/controlled-input/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "counter",
+ "version": "1.0.0",
+ "description": "",
+ "keywords": [],
+ "author": "",
+ "dependencies": {
+ "create-react-class": "^15.6.2",
+ "react": "^16.2.0",
+ "react-dom": "^16.2.0"
+ },
+ "devDependencies": {
+ "browserify": "^16.1.0"
+ }
+}
diff --git a/examples/controlled-input/src/ControlledInput.purs b/examples/controlled-input/src/ControlledInput.purs
new file mode 100644
index 0000000..2a36b73
--- /dev/null
+++ b/examples/controlled-input/src/ControlledInput.purs
@@ -0,0 +1,29 @@
+module ControlledInput where
+
+import Prelude
+
+import Data.Maybe (Maybe(..), fromMaybe, maybe)
+import Data.Nullable (toMaybe)
+import React.Basic (ReactComponent, react)
+import React.Basic.DOM as R
+import React.Basic.DOM.Events (targetValue, timeStamp)
+import React.Basic.DOM.Events as Events
+
+component :: ReactComponent {}
+component = react
+ { displayName: "Counter"
+ , initialState: { value: "hello world", timeStamp: Nothing }
+ , receiveProps: \_ _ _ -> pure unit
+ , render: \_ state setState ->
+ R.div_
+ [ R.p_ [ R.input { onChange: Events.handler (Events.preventDefault >>> Events.merge { targetValue, timeStamp }) \{ timeStamp, targetValue } ->
+ setState \_ -> { value: fromMaybe "" (toMaybe targetValue)
+ , timeStamp: Just timeStamp
+ }
+ , value: state.value
+ }
+ ]
+ , R.p_ [ R.text ("Current value = " <> show state.value) ]
+ , R.p_ (maybe [] (\ts -> [R.text ("Changed at: " <> show ts)]) state.timeStamp)
+ ]
+ }
diff --git a/generated-docs/React/Basic.md b/generated-docs/React/Basic.md
index 8a71233..7908205 100644
--- a/generated-docs/React/Basic.md
+++ b/generated-docs/React/Basic.md
@@ -3,7 +3,7 @@
#### `react`
``` purescript
-react :: forall props state fx. { displayName :: String, initialState :: { | state }, receiveProps :: props -> { | state } -> (SetState state fx) -> Eff (react :: ReactFX | fx) Unit, render :: props -> { | state } -> (SetState state fx) -> JSX } -> ReactComponent props
+react :: forall props state fx. { displayName :: String, initialState :: { | state }, receiveProps :: { | props } -> { | state } -> (SetState state fx) -> Eff (react :: ReactFX | fx) Unit, render :: { | props } -> { | state } -> (SetState state fx) -> JSX } -> ReactComponent { | props }
```
Create a React component from a _specification_ of that component.
@@ -19,7 +19,7 @@ module (and re-exported here).
#### `stateless`
``` purescript
-stateless :: forall props. { displayName :: String, render :: props -> JSX } -> ReactComponent props
+stateless :: forall props. { displayName :: String, render :: { | props } -> JSX } -> ReactComponent { | props }
```
Create a stateless React component.
@@ -30,7 +30,7 @@ components which don't use state.
#### `createElement`
``` purescript
-createElement :: forall props. ReactComponent props -> props -> JSX
+createElement :: forall props. ReactComponent { | props } -> { | props } -> JSX
```
Create a `JSX` node from a React component, by providing the props.
@@ -63,33 +63,6 @@ Render an Array of children without a wrapping component.
Provide a key when dynamically rendering multiple fragments along side
each other.
-
-### Re-exported from React.Basic.Types:
-
-#### `SyntheticEvent`
-
-``` purescript
-type SyntheticEvent = { bubbles :: Boolean, cancelable :: Boolean, currentTarget :: DOMNode, defaultPrevented :: Boolean, eventPhase :: Number, isTrusted :: Boolean, target :: DOMNode, timeStamp :: Number, "type" :: String }
-```
-
-Event data that we receive from React.
-
-#### `ReactFX`
-
-``` purescript
-data ReactFX :: Effect
-```
-
-A placeholder effect for all React FFI.
-
-#### `ReactComponent`
-
-``` purescript
-data ReactComponent :: Type -> Type
-```
-
-A React component which can be used from JavaScript.
-
#### `JSX`
``` purescript
@@ -98,28 +71,20 @@ data JSX :: Type
A virtual DOM element.
-#### `EventHandler`
+#### `ReactComponent`
``` purescript
-type EventHandler = EffFn1 (react :: ReactFX) SyntheticEvent Unit
+data ReactComponent :: Type -> Type
```
-An event handler, which receives a `SyntheticEvent` and performs some
-effects in return.
+A React component which can be used from JavaScript.
-#### `DOMNode`
+#### `ReactFX`
``` purescript
-data DOMNode :: Type
+data ReactFX :: Effect
```
-An _actual_ DOM node (not a virtual DOM element!)
-
-#### `CSS`
-
-``` purescript
-data CSS :: Type
-```
+A placeholder effect for all React FFI.
-An abstract type representing records of CSS attributes.
diff --git a/generated-docs/React/Basic/DOM.md b/generated-docs/React/Basic/DOM.md
index e79d885..3bcf6d6 100644
--- a/generated-docs/React/Basic/DOM.md
+++ b/generated-docs/React/Basic/DOM.md
@@ -15,6 +15,14 @@ text :: String -> JSX
Create a text node.
+#### `CSS`
+
+``` purescript
+data CSS :: Type
+```
+
+An abstract type representing records of CSS attributes.
+
#### `css`
``` purescript
diff --git a/generated-docs/React/Basic/DOM/Events.md b/generated-docs/React/Basic/DOM/Events.md
new file mode 100644
index 0000000..0ef5c7c
--- /dev/null
+++ b/generated-docs/React/Basic/DOM/Events.md
@@ -0,0 +1,221 @@
+## Module React.Basic.DOM.Events
+
+This module defines safe event function and property accessors.
+
+#### `EventHandler`
+
+``` purescript
+type EventHandler = EffFn1 (react :: ReactFX) SyntheticEvent Unit
+```
+
+An event handler, which receives a `SyntheticEvent` and performs some
+effects in return.
+
+#### `SyntheticEvent`
+
+``` purescript
+data SyntheticEvent :: Type
+```
+
+Event data that we receive from React.
+
+#### `DOMNode`
+
+``` purescript
+data DOMNode :: Type
+```
+
+An _actual_ DOM node (not a virtual DOM element!)
+
+#### `DOMEvent`
+
+``` purescript
+data DOMEvent :: Type
+```
+
+The underlying browser Event.
+
+#### `EventFn`
+
+``` purescript
+newtype EventFn a b
+```
+
+Encapsulates a safe event operation. `EventFn`s can be composed
+to perform multiple operations.
+
+For example:
+
+```purs
+input { onChange: handler (preventDefault >>> targetValue)
+ \value -> setState \_ -> { value }
+ }
+```
+
+##### Instances
+``` purescript
+Semigroupoid EventFn
+Category EventFn
+(IsSymbol l, RowCons l (EventFn a b) fns_rest fns, RowCons l b r_rest r, RowLacks l fns_rest, RowLacks l r_rest, Merge rest fns_rest a r_rest) => Merge (Cons l (EventFn a b) rest) fns a r
+```
+
+#### `handler`
+
+``` purescript
+handler :: forall a. EventFn SyntheticEvent a -> (a -> Eff (react :: ReactFX) Unit) -> EventHandler
+```
+
+Create an `EventHandler`, given an `EventFn` and a callback.
+
+For example:
+
+```purs
+input { onChange: handler targetValue
+ \value -> setState \_ -> { value }
+ }
+```
+
+#### `merge`
+
+``` purescript
+merge :: forall a fns fns_list r. RowToList fns fns_list => Merge fns_list fns a r => { | fns } -> EventFn a ({ | r })
+```
+
+Merge multiple `EventFn` operations and collect their results.
+
+For example:
+
+```purs
+input { onChange: handler (merge { targetValue, timeStamp })
+ \{ targetValue, timeStamp } -> setState \_ -> { ... }
+ }
+```
+
+#### `bubbles`
+
+``` purescript
+bubbles :: EventFn SyntheticEvent Boolean
+```
+
+#### `cancelable`
+
+``` purescript
+cancelable :: EventFn SyntheticEvent Boolean
+```
+
+#### `currentTarget`
+
+``` purescript
+currentTarget :: EventFn SyntheticEvent DOMNode
+```
+
+#### `eventPhase`
+
+``` purescript
+eventPhase :: EventFn SyntheticEvent Int
+```
+
+#### `eventPhaseNone`
+
+``` purescript
+eventPhaseNone :: Int
+```
+
+#### `eventPhaseCapturing`
+
+``` purescript
+eventPhaseCapturing :: Int
+```
+
+#### `eventPhaseAtTarget`
+
+``` purescript
+eventPhaseAtTarget :: Int
+```
+
+#### `eventPhaseBubbling`
+
+``` purescript
+eventPhaseBubbling :: Int
+```
+
+#### `isTrusted`
+
+``` purescript
+isTrusted :: EventFn SyntheticEvent Boolean
+```
+
+#### `nativeEvent`
+
+``` purescript
+nativeEvent :: EventFn SyntheticEvent DOMEvent
+```
+
+#### `preventDefault`
+
+``` purescript
+preventDefault :: EventFn SyntheticEvent SyntheticEvent
+```
+
+#### `isDefaultPrevented`
+
+``` purescript
+isDefaultPrevented :: EventFn SyntheticEvent Boolean
+```
+
+#### `stopPropagation`
+
+``` purescript
+stopPropagation :: EventFn SyntheticEvent SyntheticEvent
+```
+
+#### `isPropagationStopped`
+
+``` purescript
+isPropagationStopped :: EventFn SyntheticEvent Boolean
+```
+
+#### `target`
+
+``` purescript
+target :: EventFn SyntheticEvent DOMNode
+```
+
+#### `targetChecked`
+
+``` purescript
+targetChecked :: EventFn SyntheticEvent (Nullable Boolean)
+```
+
+#### `targetValue`
+
+``` purescript
+targetValue :: EventFn SyntheticEvent (Nullable String)
+```
+
+#### `timeStamp`
+
+``` purescript
+timeStamp :: EventFn SyntheticEvent Number
+```
+
+#### `type_`
+
+``` purescript
+type_ :: EventFn SyntheticEvent String
+```
+
+#### `Merge`
+
+``` purescript
+class Merge (rl :: RowList) fns a r | rl -> fns, rl a -> r where
+ mergeImpl :: RLProxy rl -> { | fns } -> EventFn a ({ | r })
+```
+
+##### Instances
+``` purescript
+Merge Nil () a ()
+(IsSymbol l, RowCons l (EventFn a b) fns_rest fns, RowCons l b r_rest r, RowLacks l fns_rest, RowLacks l r_rest, Merge rest fns_rest a r_rest) => Merge (Cons l (EventFn a b) rest) fns a r
+```
+
+
diff --git a/generated-docs/React/Basic/Types.md b/generated-docs/React/Basic/Types.md
deleted file mode 100644
index 4a94906..0000000
--- a/generated-docs/React/Basic/Types.md
+++ /dev/null
@@ -1,60 +0,0 @@
-## Module React.Basic.Types
-
-#### `JSX`
-
-``` purescript
-data JSX :: Type
-```
-
-A virtual DOM element.
-
-#### `ReactComponent`
-
-``` purescript
-data ReactComponent :: Type -> Type
-```
-
-A React component which can be used from JavaScript.
-
-#### `ReactFX`
-
-``` purescript
-data ReactFX :: Effect
-```
-
-A placeholder effect for all React FFI.
-
-#### `DOMNode`
-
-``` purescript
-data DOMNode :: Type
-```
-
-An _actual_ DOM node (not a virtual DOM element!)
-
-#### `CSS`
-
-``` purescript
-data CSS :: Type
-```
-
-An abstract type representing records of CSS attributes.
-
-#### `SyntheticEvent`
-
-``` purescript
-type SyntheticEvent = { bubbles :: Boolean, cancelable :: Boolean, currentTarget :: DOMNode, defaultPrevented :: Boolean, eventPhase :: Number, isTrusted :: Boolean, target :: DOMNode, timeStamp :: Number, "type" :: String }
-```
-
-Event data that we receive from React.
-
-#### `EventHandler`
-
-``` purescript
-type EventHandler = EffFn1 (react :: ReactFX) SyntheticEvent Unit
-```
-
-An event handler, which receives a `SyntheticEvent` and performs some
-effects in return.
-
-
diff --git a/src/React/Basic.purs b/src/React/Basic.purs
index 5db5353..daf2002 100644
--- a/src/React/Basic.purs
+++ b/src/React/Basic.purs
@@ -5,7 +5,9 @@ module React.Basic
, createElementKeyed
, fragment
, fragmentKeyed
- , module React.Basic.Types
+ , JSX
+ , ReactComponent
+ , ReactFX
) where
import Prelude
@@ -13,8 +15,15 @@ import Prelude
import Control.Monad.Eff (Eff, kind Effect)
import Control.Monad.Eff.Uncurried (EffFn3, mkEffFn3)
import Data.Function.Uncurried (Fn2, Fn3, mkFn3, runFn2)
-import React.Basic.Types (CSS, EventHandler, JSX, ReactComponent, ReactFX)
-import React.Basic.Types as React.Basic.Types
+
+-- | A virtual DOM element.
+foreign import data JSX :: Type
+
+-- | A React component which can be used from JavaScript.
+foreign import data ReactComponent :: Type -> Type
+
+-- | A placeholder effect for all React FFI.
+foreign import data ReactFX :: Effect
-- | Create a React component from a _specification_ of that component.
-- |
diff --git a/src/React/Basic/DOM.purs b/src/React/Basic/DOM.purs
index 680d633..64a0bcb 100644
--- a/src/React/Basic/DOM.purs
+++ b/src/React/Basic/DOM.purs
@@ -7,14 +7,17 @@
module React.Basic.DOM where
-import React.Basic (ReactComponent, createElement)
-import React.Basic.Types (CSS, JSX, EventHandler)
+import React.Basic (JSX, ReactComponent, createElement)
+import React.Basic.DOM.Events (EventHandler)
import Unsafe.Coerce (unsafeCoerce)
-- | Create a text node.
text :: String -> JSX
text = unsafeCoerce
+-- | An abstract type representing records of CSS attributes.
+foreign import data CSS :: Type
+
-- | Create a value of type `CSS` (which can be provided to the `style` property)
-- | from a plain record of CSS attributes.
-- |
@@ -2162,4 +2165,3 @@ wbr
=> Record attrs
-> JSX
wbr = createElement (unsafeCreateDOMComponent "wbr")
-
diff --git a/src/React/Basic/DOM/Events.js b/src/React/Basic/DOM/Events.js
new file mode 100644
index 0000000..29ad335
--- /dev/null
+++ b/src/React/Basic/DOM/Events.js
@@ -0,0 +1,20 @@
+"use strict";
+
+exports.unsafePreventDefault = function(e) {
+ e.preventDefault();
+ return e;
+};
+
+exports.unsafeIsDefaultPrevented = function(e) {
+ e.isDefaultPrevented();
+ return e;
+};
+
+exports.unsafeStopPropagation = function(e) {
+ e.stopPropagation();
+ return e;
+};
+
+exports.unsafeIsPropagationStopped = function(e) {
+ return e.isPropagationStopped();
+};
diff --git a/src/React/Basic/DOM/Events.purs b/src/React/Basic/DOM/Events.purs
new file mode 100644
index 0000000..ae0ea61
--- /dev/null
+++ b/src/React/Basic/DOM/Events.purs
@@ -0,0 +1,188 @@
+-- | This module defines safe event function and property accessors.
+
+module React.Basic.DOM.Events
+ ( EventHandler
+ , SyntheticEvent
+ , DOMNode
+ , DOMEvent
+ , EventFn
+ , handler
+ , merge
+ , bubbles
+ , cancelable
+ , currentTarget
+ , eventPhase
+ , eventPhaseNone
+ , eventPhaseCapturing
+ , eventPhaseAtTarget
+ , eventPhaseBubbling
+ , isTrusted
+ , nativeEvent
+ , preventDefault
+ , isDefaultPrevented
+ , stopPropagation
+ , isPropagationStopped
+ , target
+ , targetChecked
+ , targetValue
+ , timeStamp
+ , type_
+ , class Merge
+ , mergeImpl
+ ) where
+
+import Prelude
+
+import Control.Monad.Eff (Eff)
+import Control.Monad.Eff.Uncurried (EffFn1, mkEffFn1)
+import Data.Nullable (Nullable)
+import Data.Record (delete, get, insert)
+import Data.Symbol (class IsSymbol, SProxy(SProxy))
+import React.Basic (ReactFX)
+import Type.Row (kind RowList, class RowToList, class RowLacks, RLProxy(..), Cons, Nil)
+import Unsafe.Coerce (unsafeCoerce)
+
+-- | An event handler, which receives a `SyntheticEvent` and performs some
+-- | effects in return.
+type EventHandler = EffFn1 (react :: ReactFX) SyntheticEvent Unit
+
+-- | Event data that we receive from React.
+foreign import data SyntheticEvent :: Type
+
+-- | An _actual_ DOM node (not a virtual DOM element!)
+foreign import data DOMNode :: Type
+
+-- | The underlying browser Event.
+foreign import data DOMEvent :: Type
+
+-- | Encapsulates a safe event operation. `EventFn`s can be composed
+-- | to perform multiple operations.
+-- |
+-- | For example:
+-- |
+-- | ```purs
+-- | input { onChange: handler (preventDefault >>> targetValue)
+-- | \value -> setState \_ -> { value }
+-- | }
+-- | ```
+newtype EventFn a b = EventFn (a -> b)
+
+derive newtype instance semigroupoidBuilder :: Semigroupoid EventFn
+derive newtype instance categoryBuilder :: Category EventFn
+
+-- | Create an `EventHandler`, given an `EventFn` and a callback.
+-- |
+-- | For example:
+-- |
+-- | ```purs
+-- | input { onChange: handler targetValue
+-- | \value -> setState \_ -> { value }
+-- | }
+-- | ```
+handler :: forall a. EventFn SyntheticEvent a -> (a -> Eff (react :: ReactFX) Unit) -> EventHandler
+handler (EventFn fn) cb = mkEffFn1 $ fn >>> cb
+
+class Merge (rl :: RowList) fns a r | rl -> fns, rl a -> r where
+ mergeImpl :: RLProxy rl -> Record fns -> EventFn a (Record r)
+
+instance mergeNil :: Merge Nil () a () where
+ mergeImpl _ _ = EventFn \_ -> {}
+
+instance mergeCons
+ :: ( IsSymbol l
+ , RowCons l (EventFn a b) fns_rest fns
+ , RowCons l b r_rest r
+ , RowLacks l fns_rest
+ , RowLacks l r_rest
+ , Merge rest fns_rest a r_rest
+ )
+ => Merge (Cons l (EventFn a b) rest) fns a r
+ where
+ mergeImpl _ fns = EventFn \a ->
+ let EventFn inner = mergeImpl (RLProxy :: RLProxy rest) (delete l fns)
+ EventFn f = get l fns
+ in insert l (f a) (inner a)
+ where
+ l = SProxy :: SProxy l
+
+-- | Merge multiple `EventFn` operations and collect their results.
+-- |
+-- | For example:
+-- |
+-- | ```purs
+-- | input { onChange: handler (merge { targetValue, timeStamp })
+-- | \{ targetValue, timeStamp } -> setState \_ -> { ... }
+-- | }
+-- | ```
+merge
+ :: forall a fns fns_list r
+ . RowToList fns fns_list
+ => Merge fns_list fns a r
+ => Record fns
+ -> EventFn a (Record r)
+merge = mergeImpl (RLProxy :: RLProxy fns_list)
+
+bubbles :: EventFn SyntheticEvent Boolean
+bubbles = EventFn \e -> (unsafeCoerce e).bubbles
+
+cancelable :: EventFn SyntheticEvent Boolean
+cancelable = EventFn \e -> (unsafeCoerce e).cancelable
+
+currentTarget :: EventFn SyntheticEvent DOMNode
+currentTarget = EventFn \e -> (unsafeCoerce e).currentTarget
+
+eventPhase :: EventFn SyntheticEvent Int
+eventPhase = EventFn \e -> (unsafeCoerce e).eventPhase
+
+eventPhaseNone :: Int
+eventPhaseNone = 0
+
+eventPhaseCapturing :: Int
+eventPhaseCapturing = 1
+
+eventPhaseAtTarget :: Int
+eventPhaseAtTarget = 2
+
+eventPhaseBubbling :: Int
+eventPhaseBubbling = 3
+
+isTrusted :: EventFn SyntheticEvent Boolean
+isTrusted = EventFn \e -> (unsafeCoerce e).isTrusted
+
+nativeEvent :: EventFn SyntheticEvent DOMEvent
+nativeEvent = EventFn \e -> (unsafeCoerce e).nativeEvent
+
+preventDefault :: EventFn SyntheticEvent SyntheticEvent
+preventDefault = EventFn unsafePreventDefault
+
+foreign import unsafePreventDefault :: SyntheticEvent -> SyntheticEvent
+
+isDefaultPrevented :: EventFn SyntheticEvent Boolean
+isDefaultPrevented = EventFn unsafeIsDefaultPrevented
+
+foreign import unsafeIsDefaultPrevented :: SyntheticEvent -> Boolean
+
+stopPropagation :: EventFn SyntheticEvent SyntheticEvent
+stopPropagation = EventFn unsafeStopPropagation
+
+foreign import unsafeStopPropagation :: SyntheticEvent -> SyntheticEvent
+
+isPropagationStopped :: EventFn SyntheticEvent Boolean
+isPropagationStopped = EventFn unsafeIsPropagationStopped
+
+foreign import unsafeIsPropagationStopped :: SyntheticEvent -> Boolean
+
+target :: EventFn SyntheticEvent DOMNode
+target = EventFn \e -> (unsafeCoerce e).target
+
+targetChecked :: EventFn SyntheticEvent (Nullable Boolean)
+targetChecked = EventFn \e -> (unsafeCoerce e).target.checked
+
+targetValue :: EventFn SyntheticEvent (Nullable String)
+targetValue = EventFn \e -> (unsafeCoerce e).target.value
+
+timeStamp :: EventFn SyntheticEvent Number
+timeStamp = EventFn \e -> (unsafeCoerce e).timeStamp
+
+type_ :: EventFn SyntheticEvent String
+type_ = EventFn \e -> (unsafeCoerce e)."type"
diff --git a/src/React/Basic/Types.purs b/src/React/Basic/Types.purs
deleted file mode 100644
index 98ffe36..0000000
--- a/src/React/Basic/Types.purs
+++ /dev/null
@@ -1,38 +0,0 @@
-module React.Basic.Types where
-
-import Prelude
-
-import Control.Monad.Eff (kind Effect)
-import Control.Monad.Eff.Uncurried (EffFn1)
-
--- | A virtual DOM element.
-foreign import data JSX :: Type
-
--- | A React component which can be used from JavaScript.
-foreign import data ReactComponent :: Type -> Type
-
--- | A placeholder effect for all React FFI.
-foreign import data ReactFX :: Effect
-
--- | An _actual_ DOM node (not a virtual DOM element!)
-foreign import data DOMNode :: Type
-
--- | An abstract type representing records of CSS attributes.
-foreign import data CSS :: Type
-
--- | Event data that we receive from React.
-type SyntheticEvent =
- { bubbles :: Boolean
- , cancelable :: Boolean
- , currentTarget :: DOMNode
- , defaultPrevented :: Boolean
- , eventPhase :: Number
- , isTrusted :: Boolean
- , target :: DOMNode
- , timeStamp :: Number
- , type :: String
- }
-
--- | An event handler, which receives a `SyntheticEvent` and performs some
--- | effects in return.
-type EventHandler = EffFn1 (react :: ReactFX) SyntheticEvent Unit