overminddl1 / bucklescript-tea Goto Github PK
View Code? Open in Web Editor NEWTEA for Bucklescript
License: Other
TEA for Bucklescript
License: Other
I'm not sure if this is the best way to use TEA, but I've run into a runtime error in this situation:
type msg = Foo of (int * msg Tea.Cmd.t)
let msgs id = Tea.Cmd.call (fun callbacks -> ....)
let view =
div [onClick (Foo (1, (msgs 1)))] []
I get an error on
Line 154 in 51403a6
because this uses ocaml.equal which doesn't like comparing functions:
var b_type = typeof b;
if (a_type === "function" || b_type === "function") {
throw [
invalid_argument,
"equal: functional value"
Concrete question, I have a redux app and parts of it I want to port to bucklescript. This is not that hard, for example I can just switch the reducer with an update function.
The problem is when I have an update function that next to the model also returns msgs and I want to execute them.
I was fiddling around a bit with Tea_cmd.js to call them or run them, but honestly I'm a bit lost and maybe I need to take a step back, but I thought it is worth a shot...
So I'm not sure that it's a good idea what I'm doing, and maybe I need a different approach, but if you have any pointers if it's possible to integreate the tea loop with reducers that would help :)
So, I've been working a bit on a simple "time travel debugger" like the one in Elm.
A small demo is available at https://neochrome.github.io/debug2/
Example usage:
let () =
let module D = Debug.Make(struct
type flags = unit
type msg = my_msg
type model = my_model
let init = init
let update = update
let view = view
let subscriptions = subscriptions
let string_of_msg = function
| Increment -> "Increment"
| Decrement -> "Decrement"
| Reset -> "Reset"
| Set _ -> "Set"
end) in
D.standardProgram (Web.Document.getElementById "main") () |> ignore;;
Is this something that would be of interest to include in the core bucklescript-tea
package or is better off as a peer package that might be added if needed?
Your thoughts?
bucklescript-tea/src/web_xmlhttprequest.ml:
let open_ method' url ?(async=true) ?(user="") ?(password="") x =
x##open_ method' url async user password
function open_(method$prime, url, $staropt$star, $staropt$star$1, $staropt$star$2, x) {
var async = $staropt$star ? $staropt$star[0] : /* true */1;
var user = $staropt$star$1 ? $staropt$star$1[0] : "";
var password = $staropt$star$2 ? $staropt$star$2[0] : "";
return x.open_(method$prime, url, async, user, password);
}
Which should be:
xhrReq.open(method, url);
xhrReq.open(method, url, async);
xhrReq.open(method, url, async, user);
xhrReq.open(method, url, async, user, password);
Could you add a repo with a small skeleton project, with the javascript pipeline (bundler, watcher etc.) configured and working? It would be a big help for people not coming from the javascript world.
This is just a question. I was wondering if it would be possible (and be useful) to create tea with React as the view layer.
The reason why it could be useful for me is: some of the hooks that react has (for example componentDidMount) are useful when you integrate with existing js code. This is something I don't know how to do with the current vdom layer.
Other reasons why it can be useful:
I haven't thought this through completely so there might be some obvious downsides or reasons why this isn't a good idea, so I'd love to get an opinion on this.
[6/27] Building src/web_location.cmj /Users/jackalcooper/elixir/node_modules/bucklescript-tea/lib/js/src/web_location.js src/web_location.cmi
FAILED: src/web_location.cmj /Users/jackalcooper/elixir/node_modules/bucklescript-tea/lib/js/src/web_location.js src/web_location.cmi
/Users/jackalcooper/elixir/missing_pieces/assets/node_modules/bs-platform/bin/bsc.exe -bs-package-name bucklescript-tea -bs-package-output commonjs:lib/js/src -bs-assume-no-mli -bs-no-builtin-ppx-ml -bs-no-implicit-include -I src -nostdlib -I '/Users/jackalcooper/elixir/node_modules/bs-platform/lib/ocaml' -bs-cross-module-opt -no-alias-deps -color always -w -40+6+7+27+32..39+44+45 -o src/web_location.mlast -c src/web_location.mlast
File "/Users/jackalcooper/elixir/node_modules/bucklescript-tea/src/web_location.ml", line 3, characters 9-433:
Error: Unbound module Js.Internal
ninja: build stopped: subcommand failed.
Failure: /Users/jackalcooper/elixir/missing_pieces/assets/node_modules/bs-platform/bin/ninja.exe
Location: /Users/jackalcooper/elixir/node_modules/bucklescript-tea/lib/bs
Error happened when running command /Users/jackalcooper/elixir/missing_pieces/assets/node_modules/bs-platform/bin/bsb.exe with args [ '-make-world', '-w' ]
Standard states that boolean attribute must not have their value set to true, but instead must be either empty or a case-insensitive version of their own name, "true" and "false" (not used here) are not valid.
When I compile with BS 1.5.0 the following function breaks:
function setStyleProperty(n, $staropt$star, key, value) {
var priority = $staropt$star ? $staropt$star[0] : /* false */0;
var style = n.style;
var match = style.setProperty;
if (match !== undefined) {
return style.setProperty_(key, value, priority ? "important" : null);
}
else {
return setStyle(n, key, value);
}
}
In web_node.ml there is a type definition for 'style'
type style = <
setProperty : Web_json.t Js.undefined [@bs.get]; (* TODO: Revamp this and the next line... *)
setProperty_ : string -> string Js.null -> string Js.null -> unit [@bs.meth];
> Js.t
I was about to use an Array for a part of my model, and using Belt.Array.set
as part of the update. I am worried that the TEA implementation that this is based on assumes that you're dealing with immutable arrays, like the ones built into elm.
Is bucklescript-tea robust to mutating the model in the update function? Or should we avoid using mutation and rely on immutable data structures?
Thanks!
The following statement successfully sets up a connection to a websocket server
let ws = WebSockets.WebSocket.make "ws://localhost:5858"
|> WebSockets.WebSocket.setBinaryType ArrayBuffer
|> WebSockets.WebSocket.on @@ Open
(fun _ -> Js.log "Open")
|> WebSockets.WebSocket.on @@ Close
(fun _ -> Js.log "Close")
|> WebSockets.WebSocket.on @@ Message
on_message
|> WebSockets.WebSocket.on @@ Error
(fun _ -> Js.log "error")
;;
How can bs-tea easily subscribe to on_message ?
Could we just manually trigger an update in on_message
by using some internal function in Vdom.ml
?
I do understand that such an approach might be fundamentally different from traditional TEA ---
However said approach is more logically sensible to me and allows for much more fine-grained tuning & control over the server
It can be cool that Bucklescript support SSR, this can help to improve the user experience and is helpfull for SEO
I know you (@OvermindDL1) really dislike the new ReasonML syntax. However, I'd like to make a case for embracing it.
I'm at a coding hackaway with about 25 software engineers right now. We're all building side projects and chatting and generally having a good time. So far, I've heard 3 separate people talk about Reason. I've heard 0 talk about OCaml.
There is a significant need that Reason/Bucklescript is filling in the web development community that I sense has a great deal of momentum gathering behind it. The Elm Architecture (TEA) is a great way to build web front-end code; however, Elm is not pragmatic and software engineers in my circle have mostly relegated it to a toy project. Reason, on the other hand, has great potential, and has a lot of "market fit" to use a business term.
I see a lot of people looking for TEA in Reason, but I see TEA in OCaml as "yet another friction point" in the journey of a javascript developer seeking to harness all of the goodness that the Reason+BuckleScript combo has made available.
What do you say to switching the default examples and docs to Reason? If we need to petition for changes to ReasonML, are there any specific syntax choices that would help make bucklescript-tea
more useable?
I was hoping to chain a few http requests into a task when I noticed that Elm's Http.toTask
function hasn't been adopted (or is missing).
I attempted to split the current Http.send
function into 2 parts myself:
Http.toTask
- converts the request into a taskHttp.send
- under the hood, basically does Http.toTask req |> Cmd.attempt msg
... and ran into a problem. Because of the way that Http.send
is also being used to track progress events, I don't believe the send function can technically be pulled apart into a task - correct me if I'm wrong. See the following problem lines:
https://github.com/OvermindDL1/bucklescript-tea/blob/master/src/tea_http.ml#L108-L117
I'm torn. If we can't chain api requests into a single task, we'll need to rethink how we transition pages in our SPA (arggg). At the same time, I always found Elm's progress events awkward and disconnected.
Is there a solution that I'm not seeing?
Hi!
Is ~key:_
supposed to work the same as key
in React/Value and keyed
in Elm? If yes, I have created a test case where some nodes' values are not updated even if the model changes. Here's the code:
open Tea.App
open Tea.Html
type counter = {id: int; value: int}
type model = counter list
let init () = [{id= 0; value= 0}; {id= 1; value= 1}; {id= 2; value= 2}]
type msg = Increment of int
let update model = function
| Increment id ->
Belt.List.map model (fun counter ->
if counter.id = id then {counter with value= counter.value + 1}
else counter )
let view model =
let () =
Belt.List.map model (fun counter -> counter.value) |> Belt.List.toArray
|> Js.log
in
div []
(Belt.List.map model (fun counter ->
div ~key:(string_of_int counter.id) []
[ span [] [text (" " ^ string_of_int counter.value ^ " ")]
; button [onClick (Increment counter.id)] [text "+"] ] ))
let main = beginnerProgram {model= init (); update; view}
and repo: https://github.com/utkarshkukreti/bs-tea-key-bug (just run yarn install && yarn start
and then open the link webpack prints).
If you press "+", you'll see the correctly incremented value logged to the console but the text display of the counter does not update! If I remove ~key
it updates fine.
Add a Cmd to process Javascript native Promises. They are basically just a Task so it is pretty trivial to add in a Cmd handler to it.
Lexifi's ocaml-vdom has a nice API for declaring UIs, similar to elm's but nicer in a bunch of small ways. It'd be great to have that as an alternative API for bucklescript-tea, especially since that would let people trivially experiment with both frameworks while sharing UI code.
(I might have a go at doing this myself, if I get the time, but I figured I'd put it up here first to see if people were receptive to the idea, and if someone with more bandwidth wants to get to it first :))
type model = {
selected: string option;
languages: string list
}
type message =
| Select of string
| Delete
[@@bs.deriving {accessors}]
let render_selected = function
| Some selected ->
div []
[ text ("you selected " ^ selected)
; div [onClick Delete] [text "delete selection"]]
| None -> div [] [text "Nothing selected"]
let lang l is_selected =
let baseProps = [onClick (Select l); style "color" "blue"] in
let props = if is_selected == true then (style "border" "1px solid black")::baseProps else baseProps
in
li props [text l]
let render_languages selected languages =
let is_selected selected language =
match selected with
| Some l -> language == l
| None -> false
in
let rendered = List.map (fun l -> lang l (is_selected selected l)) languages in
ul [] rendered
let update state = function
| Select lang -> { state with selected = Some lang}
| Delete -> { state with selected = None }
let view state =
div []
[ render_selected state.selected
; render_languages state.selected state.languages]
let main =
let initialState = {
selected = Some "Erlang";
languages = ["Erlang"; "Ocaml"; "Clojure"]
} in
beginnerProgram {
model = initialState;
update;
view;
}
You have a list of languages
where the first one is selected.
If a language is selected, it gets a border. Then, above the list, a delete-link is displayed to deselect the selected language.
When deleting a language by clicking on the delete-link, the border should disappear.
All other styling (blue color) should remain, due to
let baseProps = [onClick (Select l); style "color" "blue"] in
let props = if is_selected == true then (style "border" "1px solid black")::baseProps else baseProps
in ...
All style attributes on that list-item disappear, in favour of an empty style attribute.
I would expect the style to retain the "color: blue"
Unless I'm missing something pretty obvious, this looks like a bug in the vdom diffing.
[1/15] Building src/tea_cmd.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_cmd.js src/tea_cmd.cmi
[2/15] Building src/tea_sub.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_sub.js src/tea_sub.cmi
[3/15] Building src/tea_json.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_json.js src/tea_json.cmi
FAILED: src/tea_json.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_json.js src/tea_json.cmi
/Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bs-platform/bin/bsc.exe -bs-package-name bucklescript-tea -bs-package-output commonjs:lib/js/src -bs-assume-no-mli -bs-no-builtin-ppx-ml -bs-no-implicit-include -I src -nostdlib -I /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bs-platform/lib/ocaml -bs-cross-module-opt -no-alias-deps -color always -w -40+6+7+27+32..39+44+45 -o src/tea_json.mlast -c src/tea_json.mlast
File "/Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/src/tea_json.ml", line 118, characters 43-62:
Error: This expression has type 'a Js.Undefined.t -> 'a option
but an expression was expected of type Web.Json.t option -> 'b
Type 'a Js.Undefined.t = 'a Js.undefined is not compatible with type
Web.Json.t option
[4/15] Building src/tea_svg_attributes.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_svg_attributes.js src/tea_svg_attributes.cmi
[5/15] Building src/tea_html_cmds.cmj /Users/jackalcooper/elixir/subway_umbrella/apps/subway/node_modules/bucklescript-tea/lib/js/src/tea_html_cmds.js src/tea_html_cmds.cmi
My daughter is building a singer / singing-teacher feedback app and is using Reason. She will need to use some existing component for the audio player, and js-React has some (like https://github.com/souporserious/react-media-player) with convenient props
for things like track, current play position, play / pause control or notification callbacks etc.
Would much rather use bucklescript-tea than reason-react for the overall app. Any recommendation on how to connect her bs-tea to this react-js component? The simpler the better.
Thanks!
Hi,
I just thought I should ask what is the goal regarding matching the elm APIs?
I noted that for instance the Html module currently doesn't follow the elm-html module v2.0.0 with regards to how things are arranged by sub modules.
Is this something that should be considered to be updated to be more like the elm APIs, although it would be a breaking change?
Basically, can I do something like this?
type document
type element
external document : document = "" [@@bs.val]
external createElement : document -> string -> element = "" [@@bs.send]
view _ =
let elem = createElement document "div"
div [] [elem]
The reason for this is that I use a library (esri api) that attaches itself to a htmlElement. So if I create the element and then pass it, the library works, but now I want to also render that element in my app, and I don't know how to do that.
Minimal case
type msg' =
| Trigger
[@@bs.deriving {accessors}]
type model = (string option * string option)
let update' model = function
| Trigger ->
let (left, _) = model in
(left, Some "right")
let render_model = function
| (Some _, Some _) ->
input' [value "This should be on screen"] []
| _ ->
span [] [text "nothing"]
let view' model =
div []
[ button [onClick Trigger] [text "trigger rerender"]
; render_model model
]
let main =
beginnerProgram {
model = (Some "left", None);
update = update';
view = view'
}
Expected
Whenever I click the button, it should render a input
with This should be on screen
as value.
Actual
Whenever I click the button, it renders an empty span instead of the input
.
If I wrap input
inside render_model
in an extra div
, it renders correctly. I think this might be a bug in the vdom diffing? I noticed that using noNode
instead of span [] []
in the catch-all case of render_model
, fixes this
If I use code like this:
div
[styles
[("position", "absolute")
;("left", toPX swipeyStyle##left)
;("top", toPX swipeyStyle##top)
]
]
[
img [(src Swipey.image)
][]
]
(toPX swipey... resolves to values like "200px")
I get the following js error:
[Error] Invalid_argument,-3,List.fold_left2
fold_left2 (main.js:1019)
patchVNodesOnElems_PropertiesApply (main.js:1594)
patchVNodesOnElems_MutateNode (main.js:1718)
patchVNodesOnElems (main.js:1805)
patchVNodesOnElems (main.js:1805)
patchVNodesIntoElement (main.js:2084)
doRender (main.js:2366)
handler (main.js:2415)
handler (main.js:2309)
If instead, I use this code:
div
[]
[
img [(src Swipey.image)
;style "position" "absolute"
;style "left" (toPX swipeyStyle##left)
;style "top" (toPX swipeyStyle##top)
;style "width" Swipey.widthStr
][]
]
No problem.
Is this an error of mine, or somewhere else?
Separately, I also get messages like:
[Log] VDom: Failed swapping properties because the property list length changed, use `noProp` to swap properties instead, not by altering the list structure. This is a massive inefficiency until this issue is resolved. (main.js, line 1731, x2)
What is that about?
currently when user install bucklescript-tea it will also install bs-platform.
Since we have -make-world
, currently my workflow is npm install -g bs-platform
and when I install a bucklescript project, I do an npm link
then run bsb -make-world
, this would save installation time significantly, what do you think?
Note this is for discussion, lets find the best workflow for a compiled language on npm
We need a proper getting started for forks didn't have Elm background. For now I think it is a good idea to convert the official guide from Elm. If Reason version is included, it would be even more ideal.
Here is the guide: An Introduction to Elm
match clause Style s as _newProp
of Vdom.patchVNodesOnElems_PropertiesApply_Mutate
can't handle the case two lists have different lengths. It is because OCaml's List.fold_left2
will raise Invalid_argument if the two lists are determined to have different lengths.
Elm have support for SPA, it can be creat if bucklescript does the same
Basically is give support to a Router (and SSR as complement)
Regarding this error that pops up :
VDom: Failed swapping properties because the property list length changed, use
noProp
to swap properties instead, not by altering the list structure. This is a massive inefficiency until this issue is resolved.
Sometimes I know I am changing the property list length and I am happy to take the performance hit because it happens under rare circumstances.
Would it be possible to make it so I could suppress this warning when I know I really don't mind?
In Elm properties of html tags are defined as a list.
profile user =
div [ class "profile" ]
[ img [ src user.picture ] []
, span [] [ text user.name ]
]
=> class "profile", src user.picture etc.
I'm wondering if we can fully type those properties instead of using a list with:
(* bs.obj can also be used as an attribute in external declarations, as below: *)
external make_config : hi:int -> lo:int -> unit -> t = "" [@@bs.obj]
let v = make_config ~hi:2 ~lo:3
(* compiles down to *)
(* var u = {hi : 3} *)
(* var v = {hi : 3 , lo: 2} *)
Or I am overseeing something here?
This is the code to reproduce it (Bootstrap's css required).
I recorded a video to explain it because it's kind of hard for me to write it down without animation.
video
paginate.ml:
open Tea
open App
open Html
let rec range a b =
if a > b then []
else a :: range (a + 1) b
type model =
{ page : int
; pages : int
}
type msg =
| PriviousPage
| NextPage
| SelectPage of int
| SetPages of int
let init () = { page=1; pages=10 }, Cmd.none
let update model = function
| PriviousPage -> if model.page - 1 > 0 then
let newModel = {model with page = model.page - 1} in
newModel, Cmd.none
else
model, Cmd.none
| NextPage -> let pageNew = model.page + 1 in
if pageNew < model.pages + 1 then
let newModel = {model with page = pageNew} in
newModel, Cmd.none
else
model, Cmd.none
| SelectPage pageNumber ->
(if pageNumber == model.page then
let () = print_endline "Stay in the same page" in
model, Cmd.none
else
let newModel = {model with page = pageNumber} in
newModel, Cmd.none)
| SetPages newPages ->
{model with pages = newPages; page = 1}, Cmd.none
let subscriptions _model =
Sub.none
let view model =
let pages = model.pages in
div [ ]
[ input' [ type' "text"; class' "form-control"; model.pages |> string_of_int |> value; onInput (fun x ->
let newPages = try int_of_string x with _ -> 10 in
SetPages newPages) ] []
;ul [class' "pagination"]
(
let () = Js.log model.page in
let largerThanLeft = model.page - 1 >= 1 in
let smallerThanRight = model.page + 1 <= pages in
List.concat [
[ li [classList ["disabled", largerThanLeft != true]]
[ a [ href "javascript:void(0)"; onClick PriviousPage ]
[ text ([%raw "\"Previous\"" ] : string) ]
]
]
; (
List.map (fun (index) ->
li [classList ["active", index == model.page]]
[ a [ href "javascript:void(0)"; onClick (SelectPage index) ]
[ text (string_of_int index) ]
]
)
(range 1 pages)
)
; [
li [classList ["disabled", smallerThanRight != true]]
[ a [ href "javascript:void(0)"; onClick NextPage ]
[ text ([%raw "\"Next\"" ] : string) ]
]
]
]
)
]
let main =
standardProgram {
init;
update;
view;
subscriptions;
}
Recently Bucklescript has deprecated some functions without a major version bump as per NPM semver, which caused this library to break on its depended on version of bs-platform. There are more deprections and other various warnings, these should be fixed pro-actively before bs-platform removes them since a major version bump does not seem to happen as per NPM semver requirements for backwards-incompatible API changes (Please change that since Bucklescript is distributed via NPM ^.^).
Please have a look at https://github.com/neochrome/bucklescript-tea/tree/specs for a simple take on how specs/tests possible could be implemented.
For now it is expected to first be compiled using the bucklescript compiler, then executed using node (see package.json
). It's possible it could work to execute more like a script using the -bs-main
switch of the compiler, but I couldn't get it to work right away.
Would something like this be interesting?
Hi there,
I created a starter kit that uses:
https://github.com/feluxe/bs-tea-starter-kit
Took me some time to get this running and I guess it might be valuable for other newcomers.
Please leave an issue/PR if you think it needs improvement.
Could this be added to the "Starter-Kit" section in the README?
Cheers! :)
As you may know that we published an experimental stdlib which is optimized for performance and size. BuckleScript-Tea is purely OCaml, so the benefit would trickle down naturally, I wonder what's your opinion on this issue?
Pro: Better performance and smaller size, the generated code is also easier to debug
Con: The only con that I have in mind is belt is not on native yet(it is on our road map once it reaches some stability), but as a front-end library, I think it does not matter that much. SSR on nodejs is more natural than ocaml native since there are plenty of existing web servers already in NodeJS (I know OCamlOpt is much nicer, but the reality is NodeJS is running everywhere)
Perhaps I don't I understand how to use pushMsg. I'm extending the starter project like this:
in index.html:
buckle_app = starter.main(document.body);
I've added the msg AnimationUpdate to model
in Main:
open Tea_program (* needed for pushing messages into the app from JS *)
...
external pushMsg : 'a Tea_program.processMsg -> unit = "" [@@bs.val]
external buckle_app : 'a = "buckle_app" [@@bs.val]
let update_handler () =
let () = buckle_app##pushMsg (PushMsg `AnimationUpdate) in ()
When my update_handler gets called from JS, (thus calling pushMsg) the model gets set to some large negative integer.
In debugging this, I found out that
type msg =
| AnimationUpdate
...
[@@bs.deriving {accessors}]
generates an int for the accessor, rather than a function.
If instead, I have
``
type msg =
| AnimationUpdate of int
then a real accessor is generated:
function animationUpdate(param_0) {
return /* AnimationUpdate */__(0, [param_0]);
}
**and** my model doesn't get trashed (with suitable changes to references to AnimationUpdate)!
Am I doing something wrong, or is there a bug somewhere?
PS. Thanks so much for your work, it's fantastic!
I created a test at bcc32/bucklescript-tea@acc15ec.
When a vdom property is given a non-trivial value and is then changed to
noProp
, the attribute ends up having as value the string "undefined". For the
example added in this commit, the element might end up looking like:
<li lang="undefined" style="color: blue;">Ocaml</li>
I ran into this bug when I was adding and removing the href
attribute from an <a>
, which meant that clicking on the link redirected the browser to the (relative) URL "undefined", rather than doing nothing as expected.
I apologize for using an issue for this...feel free to close this.
I don't remember where I first heard about this project, but searching led me to the Elixir Forum post, the bucklescript channel in Discord, and your blog posts.
I've considered writing blog posts about Bucklescript-TEA, writing some tutorials, or contributing to documentation. Would having a dedicated place to ask questions, gauge interest in topics, etc, be worthwhile? Do any of the above-mentioned places (or this one) make sense for discussing Bucklescript-TEA?
I think the bs-platform
dependency needs to be bumped, if it's supported:
"devDependencies": {
"bs-platform": "^2.1.0",
...
}
causes the warning:
warning "[email protected]" has incorrect peer dependency "bs-platform@^1.7.5"
I get the feeling that the view function is going to be a nightmare of parentheses for folks using the ReasonML syntax:
div([], [div([], [div([], [div([], [div([], [])])])])]);
I'm curious how much effort it would be to add support for JSX (if that is even possible). I might be willing to take a stab at it if you think it's worth while.
BTW: fantastic tea conversion into Bucklescript!
I might be doing something wrong here with ocaml, but I can't seem to find a solution. If I use the model in an onChange
handler, the model is never updated (the initial model is always used).
The bug in code:
open Tea.App
open Tea.Html
type msg =
| Increment
| Set of int
[@@bs.deriving {accessors}]
let init () = 4
let update model = function
| Increment -> model + 1
| Set i -> i
let view_button title msg =
button
[ onClick msg
]
[ text title
]
let view model =
let bug foo =
print_endline (string_of_int model);
Set (int_of_string foo)
in
div
[]
[ span
[ style "text-weight" "bold" ]
[ text (string_of_int model) ]
; br []
; view_button "Increment" Increment
; input' [onChange bug] []
]
let main =
beginnerProgram {
model = init ();
update;
view;
}
Now every time you type something in the input field and press enter, the model is set to the correct value, but if you look at the console output it always prints 4.
So the model in the bug
function is never updated?
Am I doing something wrong or is this a bug.
Something that points in the direction of a bug is that if you change the onClick
handler to (bug "10")
the model has the correct value.
So this only is a problem in the onChange
handler?
Title says it all (http://package.elm-lang.org/packages/evancz/elm-html/4.0.0/Html-Events#onWithOptions).
I would create a PR, but the vdom stuff about onCB
and onMsg
is not completely clear to me.
This might turn out to be either a question or a feature request, sorry if opening an issue is not the right place to ask this (btw is there a project related forum/chat somewhere?).
I am trying to achieve auto-resizing of textareas. Resizing on value change is working fine by using something like the following:
external _auto_expand : Web.Node.t -> unit = "textarea_auto_expand" [@@bs.val]
event "input"
(fun evt ->
match Js.Undefined.toOption evt##target with
| None -> None
| Some target -> begin
_auto_expand target;
match Js.Undefined.toOption target##value with
| None -> None
| Some value -> Some (action value)
end)
I am using an external to hack around certain missing fields on Web.Node.t such as scrollHeight and others (tbh I prefer it this way since auto resizing of textareas is a hack regardless):
const textarea_auto_expand = element => {
const get_value = pixels => parseInt(pixels.substring(0, pixels.length - 2));
const style = window.getComputedStyle(element);
const min_height = get_value(style.getPropertyValue("min-height"));
element.style.height = 0;
element.style.height = Math.max(min_height, element.scrollHeight) + 'px';
};
This works great, but I also need to have _auto_expand be called when the element is inserted into the DOM. E.g. in React you would implement componentDidMount.
I have been trying to find examples in Elm where you get access to a DOM element on insertion/mount time, but have not found any.
So, the question / feature request is; is it possible to get access to an element at the moment after it is inserted into the document?
Tea_html.node
is defined as follows:
let node ?(namespace="") tagName ?(key="") ?(unique="") props nodes = fullnode namespace tagName key unique props nodes
Correct me if I'm wrong, but since the optional parameters come after a normal parameter, it's impossible to apply this function without the latter two optional parameters.
I got this:
File "_none_", line 1, characters 0-0:
Error: Package bucklescript-tea not found or bucklescript-tea/lib/ocaml does not exist or please set npm_config_prefix correctly
ninja: build stopped: subcommand failed.
package.json:
{
"repository": {},
"engine": "node 6.0.0",
"scripts": {
"deploy": "brunch build --production",
"watch": "brunch watch --stdin",
"assets:clean": "rm -rf public/assets",
"postinstall": "npm run deploy"
},
"dependencies": {
"bucklescript-tea": "^0.1.1"
},
"devDependencies": {
"babel-brunch": "~6.0.0",
"brunch": "2.7.4",
"clean-css-brunch": "~2.0.0",
"css-brunch": "~2.0.0",
"javascript-brunch": "~2.0.0",
"uglify-js-brunch": "~2.0.1",
"bs-platform": "^1.2.0",
"jquery": ">= 2.1"
}
}
bsconfig.json:
{
"name" : "trash_talk",
"version": "0.0.1",
"bs-dependencies" : ["bucklescript-tea"],
"sources" : [
{ "dir" : "app/bucklescript/trash_talk"}
],
"bsc-flags": ["-bin-annot"],
"generate-merlin" : true
}
I was looking into doing some drag/drop with html5 (https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) but this doesn't look possible yet?
Would it require a lot of effort? I guess that some work would be adding the attributes like draggable, ondragstart,... but I'm not sure how the event handlers could be implemented
When I was creating a pagination with bucklescript-tea, I found that I could never get the "next" and "previous" button right. And I found a bug. It is the case if the msg
for onClick is a if
condition it will always go with one branch (and the value of first run, but in this case below it doesn't require a parameter for the Increment
and Decrement
msg).
Here is the minimum counter example to reproduce it. The behavior should be that the counter will go down to 2
if it reach 3
:
main_counter.ml:
open Tea.App
open Tea.Html
type msg =
| Increment
| Decrement
| Reset
| Set of int
let update model = function
| Increment -> model + 1
| Decrement -> model - 1
| Reset -> 0
| Set v -> v
let view_button title msg =
button
[ onClick msg
]
[ text title
]
let view model =
div
[]
[ span
[ style "text-weight" "bold" ]
[ text (string_of_int model) ]
; br []
; view_button "Increment" (
(*Here comes the bug*)
if model >= 3 then
Decrement
else
Increment
)
; br []
; view_button "Decrement" Decrement
; br []
; view_button "Set to 42" (Set 42)
; br []
; if model <> 0 then view_button "Reset" Reset else noNode
]
let main =
beginnerProgram {
model = 0;
update;
view;
}
I tried it with Elm and on Elm it works fine:
-- Read more about this program in the official Elm guide:
-- https://guide.elm-lang.org/architecture/user_input/buttons.html
import Html exposing (beginnerProgram, div, button, text)
import Html.Events exposing (onClick)
main =
beginnerProgram { model = 0, view = view, update = update }
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (toString model) ]
, button [ onClick
(if model >= 3 then
Decrement
else
Increment)
] [ text "+" ]
]
type Msg = Increment | Decrement
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
Currently prototyping with Bucklescript TEA for a project, love it so far :)
But came across that iframes are currently not defined in the HTML module.
I cross-referenced Elm's HTML docs with the definitions in tea_html.ml, and found a small handful of tags, these were then cross-referenced against w3school's list of tags.
These are the tags I found, the scratched tags are ones that Elm defined but I could find on w3schools' list:
hr, blockquote,
code, em, b, u, sub, sup,
dl, dt, dd,
iframe, canvas, math,
address,
caption, colgroup, col,
fieldset, legend, datalist, optgroup, keygen, output, meter,
audio, video, source, track,
embed, object, param,
ins, del,
small, cite, dfn, abbr, var, samp, kbd, s, q,
ruby, rt, rp, bdi, bdo, wbr, menuitem, menu
I am posting this issue since I am not sure how else to generate these missing tags without modifying the TEA source code, and if I am to do this, then I would rather do this proper and make it into a pull-request.
If there is a better way, then I would love to hear it :)
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.