Giter VIP home page Giter VIP logo

purescript-bonsai's People

Contributors

eeue56 avatar evancz avatar grmble avatar halohalospecial avatar iznaak avatar jcollard avatar jinjor avatar laszlopandy avatar pachopepe avatar paulstatezny avatar process-bot avatar rehno-lindeque avatar rudi-c avatar shaydon avatar spicydonuts avatar srikumarks avatar thsoft avatar warry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

megamaddu

purescript-bonsai's Issues

Additional render function that produces an Array of VNodes

The current render function of Bonsai.Html always produces a single Html node - VNode msg.

Sometimes you need several html nodes though, and they end up wrapped in an artificial div.

I want a function render' that produces Array (VNode msg. Single results would be wrapped in an array, array results would be returned as is.

Performace wishlist: lazy, keyedElement

Lazy rendering to the Virtual Dom should be supported by the markup DSL.

Nice to have: enable markup DSL attributes and styles for the top element of keyedElement

Bonsai.DOM should use F

Working with (Maybe Element) in the Eff monad is cumbersome. Compare and contrast with F - it's a joy to work with.

So: Change Bonsai.DOM to use F. Also move out any dependencies on Bonsai.VirtualDom or Bonsai.Types. It should be possible to import Bonsai.DOM from those packages after the split.

  • innerHTML
  • querySelector/querySelectorAll

BONSAI Effect in client API

Currently the effects used by Bonsai.Core are exposed to the client.

It could be argued that this is an implementation detail - the client does not need to know exactly what effects are used internally. Changes are also less likely to break existing client code - less major releases in the long run. Plus the types would become muss less cumbersome to type.

Proposal: make a BONSAI effect, do not expose any other effects in externally visible code.

Compose event handlers using BrowserEvent (F a)

Data.Foreign.F composes well for decoding browser events, and it is a full monad. The approach used currently (composing event handlers by making Property a functor) does not scale well, and I don't thing there is a monad instance - so this can't be used to raise errors.

Change event handling code to compose via (F msg).

This is the opposite of #2

Tests for core functionality

There should be tests for

  • event handlers - top priority, this is the most brittle code
  • the html DSL - needs jsdom as dev dependency, so there can be test renders
  • queue of outstanding messages
  • mapping of vnode types

There should also be a testing framework for applications using bonsai.
This testing framework should probably be in a different project
so it can be a dev-dependency.

  • Must have: no browser or display required for automated tests
  • Optional: the same tests can also be run in a browser
  • Optional: they also work in zombie or casper or some other headless browser

Easier way of starting tasks from outside the update function

Starting background or init tasks from outside the update function is cumbersome - the types are ugly and you need to use coerce if any effects are in place.

In particular, this should be possible using only one function (instead of taskContext/emitMessages as of now). Since it issues a command, issueCommand ?

Export taskContext from Core

It should be possible to obtain a TaskContext for a Program, to start emitting Tasks from outside the program. Compare to Sub in Elm - e.g. a long running task that emits a message every second, or provide callbacks to external javascript libraries.

Currently, it is only possible to create TaskCmd from an event handler or from the update function (and this would need to be triggered by an initial event).

Smolder-style Html API

Directly producing VirtualDom nodes works, but the view code reads horrible.

Better alternatives would be something like the API from the Purescript-by-example book, or a modified Smolder API.

I don't think using Smolder directly would work. They have mutating event handlers and don't need to encode the type of the emitted messages in the type of the emitted nodes.

I would like to borrow their syntax, though.

Bonsai Debugger

Let's say an application wants to have something like the Elm Debugger (i.e. display a list of messages, allow to import/export this list, and be able to go backwards and forwards having the app display the state).

  • The debugger UI would have to have it's own state and messages
  • Tracking of the incoming application messages should happen in that debugging state
  • Replay of a list of messages against some starting state should ignore commands - if the commands had any effect on the state, they did this be emitting other messages. These messages will be already in our message list.
  • The list of messages can become a tree if the user rewinds the state and takes a new path
  • In replay mode, some messages may have to be filtered (e.g. clock ticks, or messages from a SSE EventSource)

One approach would be

  • Have two Bonsais, one for the debugger, one for the application under debug
  • When the debug UI is used, the application bonsai is put in "Replay Mode". It ignores any messages it receives in the normal way, can only replay messages under control of the debugger
  • If the users wants to start working normally again, he must leave replay mode. This will either remove the rest of the message list, or add a new branch to the message tree

Delay until the next render of the model

Tasks that do DOM manipulation may be run before their target elements exist - they will be rendered the next time the model is rendered, but that happens in a requestAnimationFrame.

It would be useful to have a primitive that delays into a requestAnimationFrame where the Bonsai program state is clean (a model change will make it dirty, a render will make it clean again - this is already in Core.purs)

Client Routing - setting the Location fragment

Client Routing is a thing. 2 things are needed

  • effectful Cmd for setting the location fragment
  • parsing the URL fragment on initialization

I'd put in the Cmd now. The parser should probably be in its own package

Kill plainResult

It's just Tuple emptyCommand now. And the name is backwards - it takes a plainResult and procudes a full/cmdFull/whatever one. If we have to have this, it should be fromPlainResult

Make Property a monad/functor

If Property were a monad, event handling code would be simpler and more powerful.

EventDecoder might become unnecessary.

Investigate degrading performance

Two example apps with comparable page complexity

  • todo: diff/patch in 1-2ms
  • forms-demo: diff/patch in 10-20ms

forms-demo uses an additional level of indirection in the html generation, but I suspect it's the number of event handlers on the pages.

  • in debug mode, log estimate of diff size/complexity
  • event handler performance - memoizing the handlers might help

Minimal example of running program

Hi,

Just one question:

Does it happens to have a minimal working example?

module Examples.Counter where

import Prelude
import Bonsai (domElementById, program, text)
import Bonsai.Types (Cmd(..))
import Control.Monad.Eff.Console (error)
import DOM.Node.Types (ElementId(..))
import Data.Maybe (Maybe(..))


data Msg = Inc | Dec

type Model = Int

programContainer = do
  domElementById $ ElementId "counter"

initialState :: Model
initialState = 0

update model msg = { model : model, cmd : NoCmd }

view = show >>> text

main = do
  mContainer <- programContainer
  
  case mContainer of 
    Just c -> program c update view initialState
    Nothing -> error "no container with specified id"

I came up with this, so far, but not sure how to go further

Thanks!

update functions should have the Msg first

I just noticed that Elm has the update function arguments in the order Msg -> Model.

This is actually much better than Model -> Msg. Applying only the message argument leads to a natural operation on the model.

This will break every program.

Things to think about:

  • Mapping of update results would be easier if the result was a Bifunctor - bimap/rmap instead of mapUpdateResult
  • Making UpdateResult a Tuple would give us a state function (or maybe StateT since there is an Effect in the Signature, will have to play with this)

readerTask needs a better Name

Since there is no Reader involved anymore ...

Brainstorming:

  • programmableTask - it's fully programmable
  • emitterTask - it can emit any number of messages, any number of times
  • flexibleTask, fullTask, complexTask

AsyncCmd - effectful commands

Effectful commands should be supported. Examples would be setting the focus element on the page or triggering an Ajax request and updating the page after it completes.

Make Cmd a Monoid and/or Applicative/Monad

This would make helpers at the Cmd level (e.g. focusCmd, focusSelectCmd) much much nicer to use in combination with other Cmds, e.g animations)

I think the current design of the Cmd ADT could be made into a Monoid and/or Applicative. Ap could be even made parallel. Monad should possible but would be a lot of work, and confusing to use - all those ansychronous emits.

Current aim: sequential <>, parallel <*>. No monad.

Event handlers on external elements

Support attaching (bonsai) event handlers on non-bonsai elements.

E.g. general page layout html not generated by bonsai with links/buttons that should issue bonsai commands.

VirtualDom Properties that should be Attributes

The browser DOM has 2 ways of manipulating DOM attributes: the DOM way, with methods like get/set/removeAttribute, and via properties of the JS object.

n.setAttribute('type', 'text');

n['type'] = 'text';

The Elm html library uses mostly properties (as does Bonsai.Html.Attributes - it's basically a transliteration of the Elm library). There are some attributes as well though - I presume because the property access would not work.

Some properties that maybe should be attributes:

  • type: IE errors when input type properties are set that it can't handle. E.g. using a html date input.
  • pattern: empty phantom patterns can show up on input fields, these will never validate
  • for: empty for element will prevent the associated checkbox from working

Notable properties that MUST stay properties:

  • value: setting the value after every model change only works with the property. My very first bonsai mistake, could not get it to work until I noticed that Elm is using the property ...

onSubmit: inputs with checked method are always on

onSubmit puts all the input values in a map without checking the input's checked attribute.

E.g. checkboxes are always reported as on.

  • targetValuesEvent / targetFormValuesEvent should be fixed to handle multiple values for the same key.
  • onSubmit should only take a Message. This helper encourages working without a input model

If someone really needs the old onSubmit, they can make their own alias - it's a one liner.

unitTask helper

Tasks that are executed only for side-effects are implemented using emittingTask at the moment.

However, this seems much more common than are real emittingTask that emits multiple commands.

A convenience helper unitTask might be useful.

The Great Package Split of 2018

This all-in-one package is getting a little unwieldy. Also there is a chicken-egg problem with a testing library - an external library depending on the all-in-one package can't be used for testing inside the all-in-one package.

  • purescript-bonsai-dom: Bonsai.DOM, able to work in the browser or with JSDOM
  • purescript-bonsai-vdom: Basically this repo, with everything but Bonsai.VirtualDom and Bonsai.Types deleted
  • purescript-bonsai-jsdom: pulls in JSDOM, Test.Bonsai.JSDOM as Bonsai.JSDOM. Test Bonsai.DOM here
  • purescript-bonsai: Bonsai & Bonsai.Core. Tests without Bonsai.Html Markup. Project page under gh-pages branch. This has to preserve the old history (tags!) to not break the package management.
  • purescript-bonsai-html: Bonsai.Html and below. Tests for the markup stuff.

Make sure to link the new packages to the new project home page.

Optional: All modules under their respective root module. E.g. Bonsai.EventHandlers would become Bonsai.Core.EventHandlers. But all these renames would pollute the pursuit namespace. Maybe not a good idea.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.