Skip to content

Commit 359e207

Browse files
authored
API Refactor (#44)
* new hotness * Clean up naming * Alias SetState function types * wip * Move generated code to a separate file; add findDOMNode * Add DOM functions: render, hydrate, unmount * Regenerate docs, remove JS from examples * Add docs for new DOM functions
1 parent 637eb8b commit 359e207

31 files changed

+5427
-3067
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,36 @@ bower install [email protected]:lumihq/purescript-react-basic.git
2121
Here is an example component which renders a label read from props along with a counter:
2222

2323
```purescript
24-
module React.Basic.Example where
24+
module Counter where
2525
2626
import Prelude
2727
28-
import React.Basic (ReactComponent, react)
28+
import React.Basic as React
2929
import React.Basic.DOM as R
3030
import React.Basic.Events as Events
3131
3232
-- The props for the component
33-
type ExampleProps =
33+
type Props =
3434
{ label :: String
3535
}
3636
3737
-- Create a component by passing a record to the `react` function.
3838
-- The `render` function takes the props and current state, as well as a
3939
-- state update callback, and produces a document.
40-
component :: ReactComponent ExampleProps
41-
component = react { displayName: "Counter", initialState, receiveProps, render }
40+
component :: React.Component Props
41+
component = React.component { displayName: "Counter", initialState, receiveProps, render }
4242
where
4343
initialState =
4444
{ counter: 0
4545
}
4646
47-
receiveProps _ _ _ =
47+
receiveProps _ =
4848
pure unit
4949
50-
render props state setState =
50+
render { props, state, setState } =
5151
R.button
5252
{ onClick: Events.handler_ do
53-
setState \s -> s { counter = s.counter + 1 }
53+
setState \s -> s { counter = s.counter + 1 }
5454
, children: [ R.text (props.label <> ": " <> show state.counter) ]
5555
}
5656
```

bower.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
"purescript-nullable": "^4.0.0",
1818
"purescript-typelevel-prelude": "^3.0.0",
1919
"purescript-record": "^1.0.0",
20-
"purescript-effect": "^2.0.0"
20+
"purescript-effect": "^2.0.0",
21+
"purescript-web-events": "^1.0.0",
22+
"purescript-web-dom": "^1.0.0",
23+
"purescript-exceptions": "^4.0.0"
24+
},
25+
"devDependencies": {
26+
"purescript-web-html": "^1.0.0"
2127
}
2228
}

codegen/index.js

+22-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
1+
const fs = require('fs');
12
const { props, voids, types, reserved } = require('./consts');
3+
const genFile = "../src/React/Basic/DOM/Generated.purs";
4+
5+
const header = `-- | ----------------------------------------
6+
-- | THIS FILE IS GENERATED -- DO NOT EDIT IT
7+
-- | ----------------------------------------
8+
9+
module React.Basic.DOM.Generated where
10+
11+
import Prim.Row (class Union)
12+
import React.Basic (JSX, element)
13+
import React.Basic.DOM.Internal (SharedProps, unsafeCreateDOMComponent)
14+
import React.Basic.Events (EventHandler)
15+
16+
`;
217

318
const printRecord = (elProps) => elProps.length ? `
419
( ${ elProps.map((p) =>
520
`${p} :: ${types[p] || "String"}`).join("\n , ")
621
}
722
)` : "()"
823

9-
props.elements.html
24+
const domTypes = props.elements.html
1025
.map((e) => {
1126
const noChildren = voids.includes(e);
1227
const symbol = reserved.includes(e) ? `${e}'` : e;
@@ -20,11 +35,15 @@ props.elements.html
2035
. Union attrs attrs_ (SharedProps Props_${e})
2136
=> Record attrs
2237
-> JSX
23-
${symbol} = createElement (unsafeCreateDOMComponent "${e}")${
38+
${symbol} = element (unsafeCreateDOMComponent "${e}")${
2439
noChildren ? "" : `
2540
2641
${e}_ :: Array JSX -> JSX
2742
${e}_ children = ${symbol} { children }`
2843
}
2944
`;
30-
}).forEach((x) => console.log(x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n")))
45+
}).map((x) => x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n")).join("\n");
46+
47+
console.log(`Writing "${genFile}" ...`);
48+
fs.writeFileSync(genFile, header + domTypes);
49+
console.log("Done.");

examples/component/Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
all: node_modules
22
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
3-
purs bundle --module Container output/*/*.js > output/bundle.js
4-
echo 'module.exports = PS.Container;' >> output/bundle.js
5-
node_modules/.bin/browserify output/bundle.js index.js -o html/index.js
3+
purs bundle output/*/*.js > output/bundle.js
4+
echo 'PS.Main.main();' >> output/bundle.js
5+
node_modules/.bin/browserify output/bundle.js -o html/index.js
66

77
node_modules:
88
npm install
9+

examples/component/index.js

-10
This file was deleted.

examples/component/package.json

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
{
2-
"name": "component",
3-
"version": "1.0.0",
4-
"description": "",
5-
"keywords": [],
6-
"author": "",
72
"dependencies": {
8-
"react": "^16.2.0",
9-
"react-dom": "^16.2.0"
3+
"react": "^16.4.2",
4+
"react-dom": "^16.4.2"
105
},
116
"devDependencies": {
12-
"browserify": "^16.1.0"
7+
"browserify": "^16.2.2"
138
}
149
}

examples/component/src/Container.purs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
module Container where
22

3-
import React.Basic (ReactComponent, createElement, stateless)
3+
import React.Basic as React
44
import React.Basic.DOM as R
55
import ToggleButton as ToggleButton
66

7-
component :: ReactComponent {}
8-
component = stateless { displayName: "Container", render }
7+
component :: React.Component {}
8+
component = React.stateless { displayName: "Container", render }
99
where
1010
render _ =
1111
R.div
1212
{ children:
13-
[ createElement ToggleButton.component { on: true }
14-
, createElement ToggleButton.component { on: false }
13+
[ React.element ToggleButton.component { on: true }
14+
, React.element ToggleButton.component { on: false }
1515
]
1616
}

examples/component/src/Main.purs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Container as Container
6+
import Data.Maybe (Maybe(..))
7+
import Effect (Effect)
8+
import Effect.Exception (throw)
9+
import React.Basic (element)
10+
import React.Basic.DOM (render)
11+
import Web.DOM.NonElementParentNode (getElementById)
12+
import Web.HTML (window)
13+
import Web.HTML.HTMLDocument (toNonElementParentNode)
14+
import Web.HTML.Window (document)
15+
16+
main :: Effect Unit
17+
main = do
18+
container <- getElementById "container" =<< (map toNonElementParentNode $ document =<< window)
19+
case container of
20+
Nothing -> throw "Container element not found."
21+
Just c ->
22+
let app = element Container.component {}
23+
in render app c

examples/component/src/ToggleButton.purs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@ module ToggleButton where
22

33
import Prelude
44

5-
import React.Basic (ReactComponent, react)
5+
import React.Basic as React
66
import React.Basic.DOM as R
77
import React.Basic.Events as Events
88

9-
type ExampleProps =
9+
type Props =
1010
{ on :: Boolean
1111
}
1212

13-
component :: ReactComponent ExampleProps
14-
component = react { displayName: "ToggleButton", initialState, receiveProps, render }
13+
component :: React.Component Props
14+
component = React.component { displayName: "ToggleButton", initialState, receiveProps, render }
1515
where
1616
initialState =
1717
{ on: false }
1818

19-
receiveProps props _ setState =
19+
receiveProps { props, setState } =
2020
setState _ { on = props.on }
2121

22-
render _ state setState =
22+
render { state, setState } =
2323
R.button
2424
{ onClick: Events.handler_ (setState \s -> s { on = not s.on })
2525
, children: [ R.text if state.on then "On" else "Off" ]

examples/controlled-input/Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
all: node_modules
22
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
3-
purs bundle --module ControlledInput output/*/*.js > output/bundle.js
4-
echo 'module.exports = PS.ControlledInput;' >> output/bundle.js
5-
node_modules/.bin/browserify output/bundle.js index.js -o html/index.js
3+
purs bundle output/*/*.js > output/bundle.js
4+
echo 'PS.Main.main();' >> output/bundle.js
5+
node_modules/.bin/browserify output/bundle.js -o html/index.js
66

77
node_modules:
88
npm install
9+

examples/controlled-input/index.js

-10
This file was deleted.
+3-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
{
2-
"name": "counter",
3-
"version": "1.0.0",
4-
"description": "",
5-
"keywords": [],
6-
"author": "",
72
"dependencies": {
8-
"create-react-class": "^15.6.2",
9-
"react": "^16.2.0",
10-
"react-dom": "^16.2.0"
3+
"react": "^16.4.2",
4+
"react-dom": "^16.4.2"
115
},
126
"devDependencies": {
13-
"browserify": "^16.1.0"
7+
"browserify": "^16.2.2"
148
}
159
}

examples/controlled-input/src/ControlledInput.purs

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@ module ControlledInput where
33
import Prelude
44

55
import Data.Maybe (Maybe(..), fromMaybe, maybe)
6-
import React.Basic (ReactComponent, fragment, react)
6+
import React.Basic as React
77
import React.Basic.DOM as R
88
import React.Basic.DOM.Events (preventDefault, targetValue, timeStamp)
99
import React.Basic.Events as Events
1010

11-
component :: ReactComponent {}
12-
component = react { displayName: "ControlledInput", initialState, receiveProps, render }
11+
component :: React.Component {}
12+
component = React.component { displayName: "ControlledInput", initialState, receiveProps, render }
1313
where
1414
initialState =
1515
{ value: "hello world"
1616
, timeStamp: Nothing
1717
}
1818

19-
receiveProps _ _ _ =
19+
receiveProps _ =
2020
pure unit
21-
22-
render _ state setState =
23-
fragment
21+
22+
render { state, setState } =
23+
React.fragment
2424
[ R.input
2525
{ onChange:
2626
Events.handler
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import ControlledInput as ControlledInput
6+
import Data.Maybe (Maybe(..))
7+
import Effect (Effect)
8+
import Effect.Exception (throw)
9+
import React.Basic (element)
10+
import React.Basic.DOM (render)
11+
import Web.DOM.NonElementParentNode (getElementById)
12+
import Web.HTML (window)
13+
import Web.HTML.HTMLDocument (toNonElementParentNode)
14+
import Web.HTML.Window (document)
15+
16+
main :: Effect Unit
17+
main = do
18+
container <- getElementById "container" =<< (map toNonElementParentNode $ document =<< window)
19+
case container of
20+
Nothing -> throw "Container element not found."
21+
Just c ->
22+
let app = element ControlledInput.component {}
23+
in render app c

examples/counter/Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
all: node_modules
22
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
3-
purs bundle --module Counter output/*/*.js > output/bundle.js
4-
echo 'module.exports = PS.Counter;' >> output/bundle.js
5-
node_modules/.bin/browserify output/bundle.js index.js -o html/index.js
3+
purs bundle output/*/*.js > output/bundle.js
4+
echo 'PS.Main.main();' >> output/bundle.js
5+
node_modules/.bin/browserify output/bundle.js -o html/index.js
66

77
node_modules:
88
npm install

examples/counter/index.js

-10
This file was deleted.

examples/counter/package.json

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
{
2-
"name": "counter",
3-
"version": "1.0.0",
4-
"description": "",
5-
"keywords": [],
6-
"author": "",
72
"dependencies": {
8-
"create-react-class": "^15.6.2",
9-
"react": "^16.2.0",
10-
"react-dom": "^16.2.0"
3+
"react": "^16.4.2",
4+
"react-dom": "^16.4.2"
115
},
126
"devDependencies": {
13-
"browserify": "^16.1.0"
7+
"browserify": "^16.2.2"
148
}
159
}

0 commit comments

Comments
 (0)