outwatch / purescript-outwatch Goto Github PK
View Code? Open in Web Editor NEWA functional and reactive UI framework based on Rx and VirtualDom
Home Page: https://outwatch.github.io/?lang=purescript
License: Apache License 2.0
A functional and reactive UI framework based on Rx and VirtualDom
Home Page: https://outwatch.github.io/?lang=purescript
License: Apache License 2.0
based on #7 and #3, I gave a try to some alternative monadic API
๐ operators like ==>
, <==
, and :=
are gone
๐ no more [,,,]
lists neither
it seems to works well.
the only thing missing seems to be some
instance childReceiverBuilder2 :: ReceiverBuilder ChildStreamReceiverBuilder (Observable (VDomBuilder e)) e where
instance childrenStreamReceiverBuilder2 :: (Traversable t) => ReceiverBuilder ChildrenStreamReceiverBuilder (Observable (t (VDomBuilder e))) e where
so components can still create dynamically subcomponents with personal handlers for inner state management.
@LukaJCB how does it look ?
module Main where
-- import OutWatch
import Prelude
import OutWatch.Sink as Sink
import RxJS.Observable as Observable
import Builder (class AttributeBuilder, class ReceiverBuilder)
import Control.Alt (map)
import Control.Monad.Aff.Console (CONSOLE)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (log, logShow)
import Control.Monad.RWS.Trans (lift)
import Control.Monad.State (class MonadState, State, StateT(..), execState, execStateT, modify)
import DOM.Node.Types (Element)
import Data.Array (cons, snoc, replicate)
import Data.Array.Partial (head)
import Data.CommutativeRing ((+))
import Data.EuclideanRing ((/))
import Data.Int (round)
import Data.Monoid ((<>))
import Data.Unit (Unit)
import EmitterBuilder (class EmitterBuilder, emitFrom)
import OutWatch (children, createHandler, li, render, src, ul, valueShow, (==>))
import OutWatch (childShow, createNumberHandler, div, img, (:=))
import OutWatch.Attributes (inputNumber, insert, max, text, tpe, (<==))
import OutWatch.Sink (Handler, Observer(..), SinkLike, create)
import OutWatch.Tags (br, hr, input)
import Partial.Unsafe (unsafePartial)
import R.Yolo (x)
import RxJS.Observable (Observable, combineLatest, interval, startWith)
import VDomModifier (VDom)
main :: Eff _ Unit
main = do
log "start"
-- render "#app" app
(unsafeFirst <$> build test) >>= render "#app"
log "done"
test2 :: forall e. Number -> VDomBuilder e Unit
test2 max = do
let def = 0.0
h <- createHandlerE [def]
let imageLists = h.src # map (\n -> replicate (round n) (img[src := "img.svg"]))
ul_ do
input_ do
type_ "range"
inputNumber_ h
valueShow_ def
max_ max
div_ (children_ imageLists)
div_ (childShow_ h.src)
test :: forall e. VDomBuilder e Unit
test = ul_ do
h <- createHandlerE [2.0]
input_ do
type_ "number"
inputNumber_ h
hr_ (pure unit)
li_ do
text_ "the cat is "
text_ "nice"
li_ (text_ "yay")
li_ do
text_ "sub elements"
ul_ do
li_ (text_ "ok")
li_ (text_ "ok")
li_ (test2 1.0)
li_ (test2 3.0)
----------------------------------------------------------------------------
---- types -----------------------------------------------------------------
foreign import data H :: !
type VDomBuilder e a = StateT (Array (VDom e)) (Eff (h::H|e)) a
type NodeBuilder e = VDomBuilder e Unit -> VDomBuilder e Unit
----------------------------------------------------------------------------
-- Handlers, Observables, Sinks --------------------------------------------
createHandlerE :: forall a e. Array a -> VDomBuilder e (Handler e a)
createHandlerE a = lift $ pure (createHandler a)
----------------------------------------------------------------------------
-- Elements ----------------------------------------------------------------
wrapElem :: forall e. (Array (VDom e) -> (VDom e)) -> VDomBuilder e Unit -> VDomBuilder e Unit
wrapElem e b = lift (e <$> execStateT b []) >>= push
ul_ :: forall e. NodeBuilder e
ul_ = wrapElem ul
li_ :: forall e. NodeBuilder e
li_ = wrapElem li
div_ :: forall e. NodeBuilder e
div_ = wrapElem div
br_ = wrapElem br
hr_ = wrapElem hr
input_ :: forall e. NodeBuilder e
input_ = wrapElem input
text_ :: forall e. String -> VDomBuilder e Unit
text_ t = push (text t)
-- ul_1 :: forall e. VDomBuilder e Unit -> VDomBuilder e Unit
-- ul_1 b = lift (ul <$> execStateT b []) >>= push
----------------------------------------------------------------------------
-- Attributes --------------------------------------------------------------
wrapAttribyte ::
forall builder value e.
AttributeBuilder builder value =>
builder ->
value ->
VDomBuilder e Unit
wrapAttribyte b v = push (b := v)
type_ :: forall e. String -> VDomBuilder e Unit
type_ = wrapAttribyte tpe
valueShow_ :: forall s e. Show s => s -> VDomBuilder e Unit
valueShow_ = wrapAttribyte valueShow
max_ :: forall e. Number -> VDomBuilder e Unit
max_ = wrapAttribyte max
----------------------------------------------------------------------------
-- Emitter -----------------------------------------------------------------
wrapEmitter :: forall builder a e r.
EmitterBuilder builder a e =>
builder ->
SinkLike e a r ->
VDomBuilder e Unit
wrapEmitter b s = push (b ==> s)
-- inputNumber_ :: forall e. Number -> VDomBuilder e Unit
inputNumber_ = wrapEmitter inputNumber
----------------------------------------------------------------------------
-- Receiver ----------------------------------------------------------------
wrapReceiver :: forall builder stream e.
ReceiverBuilder builder stream e =>
builder ->
stream ->
VDomBuilder e Unit
wrapReceiver b s = push (b <== s)
children_ :: forall e. Observable (Array (VDom e)) -> VDomBuilder e Unit
children_ s = push (children <== s)
-- instance childReceiverBuilder :: ReceiverBuilder ChildStreamReceiverBuilder (Observable (VDom e)) e where
-- bindFrom builder obs =
-- let valueStream = map modifierToVNode obs
-- in Receiver (ChildStreamReceiver valueStream)
-- children_2 :: forall e. Observable (VDomBuilder e Unit) -> VDomBuilder e Unit
-- children_2 = do
-- children
childShow_ :: forall a e. Show a => Observable a -> VDomBuilder e Unit
childShow_ = wrapReceiver childShow
-- ReceiverBuilder builder stream eff | stream -> eff, builder -> stream where
-- bindFrom :: builder -> stream -> VDom eff
----------------------------------------------------------------------------
-- Helpers -----------------------------------------------------------------
push :: forall vdom m. (MonadState (Array vdom) m) => vdom -> m Unit
push = (\e l -> snoc l e) >>> modify
unsafeFirst :: forall a. Array a -> a
unsafeFirst a = unsafePartial (head a)
build :: forall e a. VDomBuilder e a -> Eff (h::H|e) (Array (VDom e))
build b = execStateT b []
------------------------------------------------------------------------------
---- old ---------------------------------------------------------------------
app :: forall e. VDom ( console :: CONSOLE | e )
app = div
[ root 1.0
, root 12.0
, root 100.0
]
root :: forall e. Number -> VDom (console :: CONSOLE |e)
root a = ul
[ input
[ tpe := "range"
, inputNumber ==> sliderEvents
, valueShow := 0
, max := a
]
, div [children <== imageLists]
, div [childShow <== sliderEvents.src]
, div [childShow <== sliderEvents.src]
, div [childShow <== sliderEvents.src]
]
where
imageLists = sliderEvents.src
# map round
# map (\n -> replicate n (img[src := "img.svg"]))
sliderEvents :: forall e. Handler e Number
sliderEvents = createHandler [0.0]
I love OutWatch's overall design, but have some issues with consistency, modules organisation, and naming clashes (I saw the latests re-organisation commits, but I think there is more to discuss)
Purescript
names like div
are really annoying to use because they clash with prelude.
name like tpe
are also annoying to use because they are harder to remember
would it make sense to follow lucid design and prefix or postfix everything with an _
?
it could also help adding back an global OutWatch
that reexport most useful functions
(to see some more lucid examples, github link is here: https://github.com/chrisdone/lucid)
OS: macOS 10.12.4
npm: 3.10.10
purescript-outwatch: 0.7.0
Run:
npm install -g purescript pulp bower
pulp init
bower install purescript-outwatch
npm install rxjs snabbdom
Edit src/Main.purs
:
module Main where
import OutWatch
main = render "#app" (h1 [text "Hello World"])
Create index.html
:
<body>
<div id="app"></div>
<script type="text/javascript" src="index.js"></script>
</body>
Run:
pulp --watch browserify --to index.js
Output:
Error 1 of 3:
in module RxJS.Observable
at bower_components/purescript-rxps/src/RxJS/Observable.purs line 117, column 1 - line 117, column 52
Module Test.QuickCheck was not found.
Make sure the source file exists, and that it has been provided as an input to psc.
See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
or to contribute content related to this error.
Error 2 of 3:
in module RxJS.Observable
at bower_components/purescript-rxps/src/RxJS/Observable.purs line 118, column 1 - line 118, column 37
Module Test.QuickCheck.Gen was not found.
Make sure the source file exists, and that it has been provided as an input to psc.
See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
or to contribute content related to this error.
Error 3 of 3:
in module Main
at src/Main.purs line 3, column 1 - line 3, column 16
Module OutWatch was not found.
Make sure the source file exists, and that it has been provided as an input to psc.
See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
or to contribute content related to this error.
* ERROR: Subcommand terminated with exit code 1
From what I understand, as of now, it's only working because of purescript lack of optimisation.
both inlining and caching should break the code.
Am I missing something ?
edit: Is there something related to strictness I'm not understanding here ?
should it be something along the lines of:
createHandler :: forall a e. Array a -> Eff (rx :: RX) (Handler e a)
Do you plan to add helpers like
inputRange :: forall e. Array (VDom e) -> VDom e
inputRange opts = input (cons (tpe := "number") opts)
?
If not, would you accept a PR with some of those ?
When trying to build one of the examples, I'm running into the following issues, which seem related to the purescript 0.11 transition:
Using pulp 11.0.0, purescript 0.11.4, if I do:
git clone https://github.com/OutWatch/purescript-outwatch
cd purescript-outwatch
npm install
bower install
npm run build:example-counter
I get:
The following values are not defined in the foreign module for module RxJS.BehaviorSubject:
_empty
* ERROR: Subcommand terminated with exit code 1
npm ERR! Darwin 16.5.0
npm ERR! argv "/usr/local/Cellar/node/7.2.1/bin/node" "/usr/local/bin/npm" "run" "build:example-counter-store"
npm ERR! node v7.2.1
npm ERR! npm v4.0.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build:example-counter-store: `npm run clean:output && pulp browserify --optimise --include examples/counter-store/src --to examples/counter-store/dist/app.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build:example-counter-store script 'npm run clean:output && pulp browserify --optimise --include examples/counter-store/src --to examples/counter-store/dist/app.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the purescript-outwatch package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! npm run clean:output && pulp browserify --optimise --include examples/counter-store/src --to examples/counter-store/dist/app.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs purescript-outwatch
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls purescript-outwatch
npm ERR! There is likely additional logging output above.
If I try to set up a fresh project with:
pulp init
bower install purescript-outwatch
I get a long list of dialogs, this being the first:
Unable to find a suitable version for purescript-prelude, please choose one by typing one of the numbers below:
1) purescript-prelude#^2.1.0 which resolved to 2.5.0 and is required by purescript-control#2.0.0, purescript-dom#3.8.1, purescript-eff#2.0.0, purescript-functions#2.0.0, purescript-invariant#2.0.0, purescript-newtype#1.3.0, purescript-outwatch#0.6.1
2) purescript-prelude#^2.5.0 which resolved to 2.5.0 and is required by purescript-either#2.2.1, purescript-maybe#2.1.1
3) purescript-prelude#^2.3.0 which resolved to 2.5.0 and is required by purescript-snabbdom#0.2.3
4) purescript-prelude#^2.0.0 which resolved to 2.5.0 and is required by purescript-form-urlencoded#2.0.0
5) purescript-prelude#^2.4.0 which resolved to 2.5.0 and is required by purescript-tuples#3.2.0
6) purescript-prelude#^3.0.0 which resolved to 3.0.0 and is required by outw2, purescript-control#3.0.0, purescript-dom#4.3.1, purescript-eff#3.1.0, purescript-either#3.0.0, purescript-functions#3.0.0, purescript-invariant#3.0.0, purescript-maybe#3.0.0, purescript-newtype#2.0.0, purescript-nonempty#4.0.0, purescript-rxjs#eaf9609267, purescript-tuples#4.0.0
If I'm answering all with the highest option (6 in the above case) - which should give me PS 11 compatibility(?), and then run:
pulp build
I get:
Error 1 of 5:
at bower_components/purescript-affjax/src/Network/HTTP/Affjax.purs line 58, column 1 - line 58, column 1
Unable to parse module:
The `!` symbol is no longer used for the kind of effects.
The new equivalent is the named kind `Effect`, defined in `Control.Monad.Eff` in the `purescript-eff` library.
See https://github.com/purescript/documentation/blob/master/errors/ErrorParsingModule.md for more information,
or to contribute content related to this error.
Error 2 of 5:
at bower_components/purescript-affjax/src/Network/HTTP/Affjax/Request.purs line 30, column 1 - line 30, column 1
Unable to parse module:
The `*` symbol is no longer used for the kind of types.
The new equivalent is the named kind `Type`.
See https://github.com/purescript/documentation/blob/master/errors/ErrorParsingModule.md for more information,
or to contribute content related to this error.
plus 3 more errors related to PS 0.11 issues.
I eventually could get an example built by setting the critical libs as direct dependencies:
"dependencies": {
"purescript-prelude": "^3.0.0",
"purescript-console": "^3.0.0",
"purescript-eff": "^3.1.0",
"purescript-snabbdom": "^1.0.0",
"purescript-affjax": "^4.0.0",
"purescript-foldable-traversable": "^3.0.0",
"purescript-argonaut-core": "^3.1.0",
"purescript-outwatch": "^0.6.1",
"purescript-quickcheck": "^4.0.0",
"purescript-rxjs": "https://github.com/LukaJCB/purescript-rxjs.git"
pulp browserify --to index.js
then succeeds, however when loading the bundle in the bowser I get a multitude of errors like:
Uncaught TypeError: Cannot read property 'id' of undefined
at emptyNodeAt (index.js:18128)
at patch (index.js:18367)
at index.js:41565
at index.js:19510
at index.js:19510
at index.js:19510
at SafeSubscriber._next (index.js:40681)
at SafeSubscriber.__tryOrSetError (index.js:1284)
at SafeSubscriber.next (index.js:1226)
at Subscriber._next (index.js:1166)
Sorry for this totally offtopic question. I was just super curious. You already did it in two languages, which is awesome. Any plans for ReasonML?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.