diff --git a/README.md b/README.md index 2d0d398..565a6ac 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This package implements an opinionated set of bindings to the React library, optimizing for the most basic use cases. -## Features +## Features - All React DOM elements and attributes are supported. - An intuitive API for specifying props - no arrays of key value pairs, just records. @@ -41,7 +41,8 @@ type ExampleState = -- state update callback, and produces a document. example :: R.ReactComponent ExampleProps example = R.react - { initialState: \_ -> { counter: 0 } + { initialState: { counter: 0 } + , receiveProps: \_ _ _ -> pure unit , render: \{ label } { counter } setState -> R.button { onClick: mkEffFn1 \_ -> do setState { counter: counter + 1 } diff --git a/examples/component/.gitignore b/examples/component/.gitignore new file mode 100644 index 0000000..645684d --- /dev/null +++ b/examples/component/.gitignore @@ -0,0 +1,4 @@ +output +html/index.js +package-lock.json +node_modules diff --git a/examples/component/Makefile b/examples/component/Makefile new file mode 100644 index 0000000..a7679c9 --- /dev/null +++ b/examples/component/Makefile @@ -0,0 +1,5 @@ +all: + purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs' + purs bundle --module Container output/*/*.js > output/bundle.js + echo 'module.exports = PS.Container;' >> output/bundle.js + node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js diff --git a/examples/component/README.md b/examples/component/README.md new file mode 100644 index 0000000..cc747f4 --- /dev/null +++ b/examples/component/README.md @@ -0,0 +1,12 @@ +# Component 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/component/html/index.html b/examples/component/html/index.html new file mode 100644 index 0000000..6b93b7c --- /dev/null +++ b/examples/component/html/index.html @@ -0,0 +1,10 @@ + + + + react-basic example + + +
+ + + diff --git a/examples/component/index.js b/examples/component/index.js new file mode 100644 index 0000000..1a54c75 --- /dev/null +++ b/examples/component/index.js @@ -0,0 +1,10 @@ +"use strict"; + +var React = require("react"); +var ReactDOM = require("react-dom"); +var Container = require("./output/bundle.js"); + +ReactDOM.render( + React.createElement(Container.component, { label: 'Increment' }), + document.getElementById("container") +); diff --git a/examples/component/package.json b/examples/component/package.json new file mode 100644 index 0000000..8648b2b --- /dev/null +++ b/examples/component/package.json @@ -0,0 +1,15 @@ +{ + "name": "component", + "version": "1.0.0", + "description": "", + "keywords": [], + "author": "", + "dependencies": { + "create-react-class": "^15.6.2", + "react": "^15.6.2", + "react-dom": "^15.6.2" + }, + "devDependencies": { + "browserify": "^16.1.0" + } +} diff --git a/examples/component/src/Container.purs b/examples/component/src/Container.purs new file mode 100644 index 0000000..8ce3150 --- /dev/null +++ b/examples/component/src/Container.purs @@ -0,0 +1,16 @@ +module Container where + +import Prelude + +import React.Basic as R +import ToggleButton as ToggleButton + +component :: R.ReactComponent Unit +component = R.react + { initialState: unit + , receiveProps: \_ _ _ -> pure unit + , render: \_ _ setState -> + R.div { } [ R.component ToggleButton.component { on: true } + , R.component ToggleButton.component { on: false } + ] + } diff --git a/examples/component/src/ToggleButton.purs b/examples/component/src/ToggleButton.purs new file mode 100644 index 0000000..fd11c6e --- /dev/null +++ b/examples/component/src/ToggleButton.purs @@ -0,0 +1,24 @@ +module ToggleButton where + +import Prelude + +import Control.Monad.Eff.Uncurried (mkEffFn1) +import React.Basic as R + +type ExampleProps = + { on :: Boolean + } + +type ExampleState = + { on :: Boolean + } + +component :: R.ReactComponent ExampleProps +component = R.react + { initialState: { on: false } + , receiveProps: \{ on } _ setState -> setState { on } + , render: \_ { on } setState -> + R.button { onClick: mkEffFn1 \_ -> setState { on: not on } + } + [ R.text if on then "On" else "Off" ] + } diff --git a/examples/counter/.gitignore b/examples/counter/.gitignore new file mode 100644 index 0000000..645684d --- /dev/null +++ b/examples/counter/.gitignore @@ -0,0 +1,4 @@ +output +html/index.js +package-lock.json +node_modules diff --git a/examples/counter/Makefile b/examples/counter/Makefile new file mode 100644 index 0000000..a31aa7b --- /dev/null +++ b/examples/counter/Makefile @@ -0,0 +1,5 @@ +all: + purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs' + purs bundle --module Counter output/*/*.js > output/bundle.js + echo 'module.exports = PS.Counter;' >> output/bundle.js + node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js diff --git a/examples/counter/README.md b/examples/counter/README.md new file mode 100644 index 0000000..f2418c0 --- /dev/null +++ b/examples/counter/README.md @@ -0,0 +1,12 @@ +# Counter 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/counter/html/index.html b/examples/counter/html/index.html new file mode 100644 index 0000000..6b93b7c --- /dev/null +++ b/examples/counter/html/index.html @@ -0,0 +1,10 @@ + + + + react-basic example + + +
+ + + diff --git a/examples/counter/index.js b/examples/counter/index.js new file mode 100644 index 0000000..4fbcf78 --- /dev/null +++ b/examples/counter/index.js @@ -0,0 +1,10 @@ +"use strict"; + +var React = require("react"); +var ReactDOM = require("react-dom"); +var Counter = require("./output/bundle.js"); + +ReactDOM.render( + React.createElement(Counter.component, { label: 'Increment' }), + document.getElementById("container") +); diff --git a/examples/counter/package.json b/examples/counter/package.json new file mode 100644 index 0000000..b1ac6d8 --- /dev/null +++ b/examples/counter/package.json @@ -0,0 +1,15 @@ +{ + "name": "counter", + "version": "1.0.0", + "description": "", + "keywords": [], + "author": "", + "dependencies": { + "create-react-class": "^15.6.2", + "react": "^15.6.2", + "react-dom": "^15.6.2" + }, + "devDependencies": { + "browserify": "^16.1.0" + } +} diff --git a/examples/counter/src/Counter.purs b/examples/counter/src/Counter.purs new file mode 100644 index 0000000..724d4d6 --- /dev/null +++ b/examples/counter/src/Counter.purs @@ -0,0 +1,30 @@ +module Counter where + +import Prelude + +import Control.Monad.Eff.Uncurried (mkEffFn1) +import React.Basic as R + +-- The props for the component +type ExampleProps = + { label :: String + } + +-- The internal state of the component +type ExampleState = + { counter :: Int + } + +-- Create a component by passing a record to the `react` function. +-- The `render` function takes the props and current state, as well as a +-- state update callback, and produces a document. +component :: R.ReactComponent ExampleProps +component = R.react + { initialState: { counter: 0 } + , receiveProps: \_ _ _ -> pure unit + , render: \{ label } { counter } setState -> + R.button { onClick: mkEffFn1 \_ -> do + setState { counter: counter + 1 } + } + [ R.text (label <> ": " <> show counter) ] + } diff --git a/generated-docs/React/Basic.md b/generated-docs/React/Basic.md index 7b1ec97..bebdf3e 100644 --- a/generated-docs/React/Basic.md +++ b/generated-docs/React/Basic.md @@ -3,19 +3,27 @@ #### `react` ``` purescript -react :: forall props state. { initialState :: state, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props +react :: forall props state. { initialState :: state, receiveProps :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> Eff (react :: ReactFX) Unit, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props ``` Create a React component from a _specification_ of that component. A _specification_ consists of a state type, an initial value for that state, -and a rendering function which takes a value of that state type, additional -_props_ (which will be passed in by the user) and a state update function. +a function to apply incoming props to the internal state, and a rendering +function which takes props, state and a state update function. The rendering function should return a value of type `JSX`, which can be constructed using the helper functions provided by the `React.Basic.DOM` module (and re-exported here). +#### `component` + +``` purescript +component :: forall props. ReactComponent props -> props -> JSX +``` + +Create a `JSX` node from another React component, by providing the props. + ### Re-exported from React.Basic.DOM: diff --git a/src/React/Basic.js b/src/React/Basic.js index 02727ca..d5b68bc 100644 --- a/src/React/Basic.js +++ b/src/React/Basic.js @@ -5,7 +5,23 @@ var React = require('react'); exports.react_ = function(spec) { return React.createClass({ getInitialState: function() { - return spec.initialState(this.props); + return spec.initialState; + }, + componentDidMount: function() { + var this_ = this; + spec.receiveProps(this.props, this.state, function(newState) { + return function() { + this_.setState(newState); + }; + }); + }, + componentWillReceiveProps: function(newProps) { + var this_ = this; + spec.receiveProps(newProps, this.state, function(newState) { + return function() { + this_.setState(newState); + }; + }); }, render: function() { var this_ = this; @@ -17,3 +33,7 @@ exports.react_ = function(spec) { } }); }; + +exports.component_ = function(component, props) { + return React.createElement(component, props); +} diff --git a/src/React/Basic.purs b/src/React/Basic.purs index e12e2d0..0ee2cdd 100644 --- a/src/React/Basic.purs +++ b/src/React/Basic.purs @@ -1,5 +1,6 @@ module React.Basic ( react + , component , module React.Basic.DOM , module React.Basic.Types ) where @@ -7,14 +8,16 @@ module React.Basic import Prelude import Control.Monad.Eff (Eff, kind Effect) -import Data.Function.Uncurried (Fn3, mkFn3) +import Control.Monad.Eff.Uncurried (EffFn3, mkEffFn3) +import Data.Function.Uncurried (Fn2, runFn2, Fn3, mkFn3) import React.Basic.DOM as React.Basic.DOM import React.Basic.Types (CSS, EventHandler, JSX, ReactComponent, ReactFX) import React.Basic.Types as React.Basic.Types foreign import react_ :: forall props state - . { initialState :: props -> state + . { initialState :: state + , receiveProps :: EffFn3 (react :: ReactFX) props state (state -> Eff (react :: ReactFX) Unit) Unit , render :: Fn3 props state (state -> Eff (react :: ReactFX) Unit) JSX } -> ReactComponent props @@ -22,16 +25,32 @@ foreign import react_ -- | Create a React component from a _specification_ of that component. -- | -- | A _specification_ consists of a state type, an initial value for that state, --- | and a rendering function which takes a value of that state type, additional --- | _props_ (which will be passed in by the user) and a state update function. +-- | a function to apply incoming props to the internal state, and a rendering +-- | function which takes props, state and a state update function. -- | -- | The rendering function should return a value of type `JSX`, which can be -- | constructed using the helper functions provided by the `React.Basic.DOM` -- | module (and re-exported here). react :: forall props state - . { initialState :: props -> state + . { initialState :: state + , receiveProps :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> Eff (react :: ReactFX) Unit , render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props -react { initialState, render } = react_ { initialState, render: mkFn3 render } +react { initialState, receiveProps, render } = + react_ + { initialState + , receiveProps: mkEffFn3 receiveProps + , render: mkFn3 render + } + +foreign import component_ :: forall props. Fn2 (ReactComponent props) props JSX + +-- | Create a `JSX` node from another React component, by providing the props. +component + :: forall props + . ReactComponent props + -> props + -> JSX +component = runFn2 component_ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy