-
Notifications
You must be signed in to change notification settings - Fork 39
Remove Array JSX
"children" argument
#15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
77201da
47f086e
a0742c7
7a77a30
6662afc
8e89c14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package-lock.json binary |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,15 +4,15 @@ This package implements an opinionated set of bindings to the React library, opt | |
|
||
## Features | ||
|
||
- All React DOM elements and attributes are supported. | ||
- All React DOM elements and attributes are supported (soon, events are a work in progress). | ||
- An intuitive API for specifying props - no arrays of key value pairs, just records. | ||
- Attributes are optional, but type-checked. It is a type error to specify `href` as an integer, for example. | ||
|
||
## Getting Started | ||
|
||
You can install this package using Bower: | ||
|
||
``` | ||
```sh | ||
bower install [email protected]:lumihq/purescript-react-basic.git | ||
``` | ||
|
||
|
@@ -24,36 +24,32 @@ module React.Basic.Example where | |
import Prelude | ||
|
||
import Control.Monad.Eff.Uncurried (mkEffFn1) | ||
import React.Basic as R | ||
import React.Basic (ReactComponent, reactComponent) | ||
import React.Basic.DOM 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. | ||
-- Create a component by passing a record to the `reactComponent` function. | ||
-- The `render` function takes the props and current state, as well as a | ||
-- state update callback, and produces a document. | ||
example :: R.ReactComponent ExampleProps | ||
example = R.react | ||
example :: ReactComponent ExampleProps | ||
example = reactComponent | ||
{ initialState: { counter: 0 } | ||
, receiveProps: \_ _ _ -> pure unit | ||
, render: \{ label } { counter } setState -> | ||
R.button { onClick: mkEffFn1 \_ -> do | ||
setState { counter: counter + 1 } | ||
setState \s -> { counter: s.counter + 1 } | ||
, children: [ R.text (label <> ": " <> show counter) ] | ||
} | ||
[ R.text (label <> ": " <> show counter) ] | ||
} | ||
``` | ||
|
||
This component can be used directly from JavaScript. For example, if you are using `purs-loader`: | ||
|
||
```javascript | ||
```jsx | ||
import {example as Example} from 'React.Basic.Example.purs'; | ||
|
||
const myComponent = () => ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
const props = require('react-html-attributes'); | ||
const voids = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']; | ||
const props = require("react-html-attributes"); | ||
const voids = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]; | ||
const types = { | ||
"allowFullScreen": "Boolean", | ||
"async": "Boolean", | ||
"autoPlay": "Boolean", | ||
"capture": "Boolean", | ||
"checked": "Boolean", | ||
"children": "Array JSX", | ||
"cols": "Number", | ||
"controls": "Boolean", | ||
"default": "Boolean", | ||
|
@@ -30,29 +31,35 @@ const types = { | |
"selected": "Boolean", | ||
"size": "Number", | ||
"span": "Number", | ||
"start": "Number", | ||
"zoomAndPan": "String" | ||
"start": "Number" | ||
}; | ||
const reserved = ["module", "data", "type", "newtype", "class", "instance", "where", "derive", "if", "then", "else", "case", "of"]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we're using these as record labels, there's no need to escape keywords (at least in recent versions of PureScript). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They become function names though, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't realize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assumed I got a newer version of |
||
|
||
printRecord = (elProps) => ` | ||
printRecord = (elProps) => elProps.length ? ` | ||
( ${ elProps.map((p) => | ||
`${p} :: ${types[p] || 'String'}`).join('\n , ') | ||
`${p} :: ${types[p] || "String"}`).join("\n , ") | ||
} | ||
)` | ||
)` : "()" | ||
|
||
props.elements.html | ||
.map((e) =>` | ||
type Props_${e} = ${ | ||
props[e] | ||
? printRecord(props[e]) | ||
: '()' | ||
} | ||
.map((e) => { | ||
const noChildren = voids.includes(e); | ||
const symbol = reserved.includes(e) ? `${e}'` : e; | ||
return ` | ||
type Props_${e} = ${printRecord( | ||
(noChildren ? [] : ["children"]).concat(props[e] || []).sort() | ||
)} | ||
|
||
${e} | ||
${symbol} | ||
:: forall attrs attrs_ | ||
. Union attrs attrs_ (SharedProps Props_${e})) | ||
. Union attrs attrs_ (SharedProps Props_${e}) | ||
=> Record attrs | ||
-> Array JSX | ||
-> JSX | ||
${e} = ${voids.indexOf(e) >= 0 ? 'createElementNoChildren' : 'createElement'} "${e}" | ||
`).forEach((x) => console.log(x.replace(/^\n\ {4}/, '').replace(/\n\ {4}/g, '\n'))) | ||
${symbol} = createElement (stringComponent "${e}")${ | ||
noChildren ? "" : ` | ||
|
||
${e}_ :: Array JSX -> JSX | ||
${e}_ children = ${symbol} { children }` | ||
} | ||
`; | ||
}).forEach((x) => console.log(x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n"))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,19 @@ | ||
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 } | ||
] | ||
} | ||
module Container where | ||
|
||
import Prelude | ||
|
||
import React.Basic (ReactComponent, createElement, react) | ||
import React.Basic.DOM as R | ||
import ToggleButton as ToggleButton | ||
|
||
component :: ReactComponent Unit | ||
component = react | ||
{ displayName: "Container" | ||
, initialState: unit | ||
, receiveProps: \_ _ _ -> pure unit | ||
, render: \_ _ setState -> | ||
R.div { children: [ createElement ToggleButton.component { on: true } | ||
, createElement ToggleButton.component { on: false } | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,22 @@ | ||
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" ] | ||
} | ||
module ToggleButton where | ||
|
||
import Prelude | ||
|
||
import Control.Monad.Eff.Uncurried (mkEffFn1) | ||
import React.Basic (ReactComponent, react) | ||
import React.Basic.DOM as R | ||
|
||
type ExampleProps = | ||
{ on :: Boolean | ||
} | ||
|
||
component :: ReactComponent ExampleProps | ||
component = react | ||
{ displayName: "ToggleButton" | ||
, initialState: { on: false } | ||
, receiveProps: \{ on } _ setState -> setState (const { on }) | ||
, render: \_ { on } setState -> | ||
R.button { onClick: mkEffFn1 \_ -> setState \s -> { on: not s.on } | ||
, children: [ R.text if on then "On" else "Off" ] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,27 @@ | ||
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) ] | ||
} | ||
module Counter where | ||
|
||
import Prelude | ||
|
||
import Control.Monad.Eff.Uncurried (mkEffFn1) | ||
import React.Basic (ReactComponent, react) | ||
import React.Basic.DOM as R | ||
|
||
-- The props for the component | ||
type ExampleProps = | ||
{ label :: String | ||
} | ||
|
||
-- 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 :: ReactComponent ExampleProps | ||
component = react | ||
{ displayName: "Counter" | ||
, initialState: { counter: 0 } | ||
, receiveProps: \_ _ _ -> pure unit | ||
, render: \{ label } { counter } setState -> | ||
R.button { onClick: mkEffFn1 \_ -> do | ||
setState \s -> { counter: s.counter + 1 } | ||
, children: [ R.text (label <> ": " <> show counter) ] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it was changed back to
react
?