Giter VIP home page Giter VIP logo

Comments (5)

glennsl avatar glennsl commented on May 31, 2024 3

A fifth solution could be to add external "overloads" for each event type:

external addMouseMoveListener : _ [@bs.as "mousemove"] => (mouseEvent => unit) => unit = "addEventListener" [@@bs.send.pipe: t];

This should provide good performance, no code generated, good documentation and can be implemented incrementally. The only downside seems to be that it deviates from the DOM API, but that's not much of an issue.

from bs-webapi-incubator.

glennsl avatar glennsl commented on May 31, 2024

Indeed they are.

One possible solution, which I hinted at on Discord, is to have casting functions in each specialized event module, e.g. MouseEvent.fromEvent. This would return an option and be rather cumbersome to use though, but is simple and easy to implement.

Another solution is to use polymorphic variants as described in the BS manual, but for addEventListener (and removeEventListener) that would become an absolutely massive external declaration, and would need to be duplicated for each of the six overloads. How would that look in the docs?

A third solution is to wrap it in a function that uses an ordinary variant, e.g. addEventListener (MouseMove (fun e -> doSomethingWith (MouseEvent.clientX e)), but since EventTarget is implemented by just about everything it would cause significant code bloat.

A fourth possible solution, for some use cases at least, would be to implement each and every on... property for each applicable type, which is no small task but can be done incrementally. This covers a slightly different use case than addEventListener however, and is generally discouraged since it's very error-prone.

And finally, this is just one of many issues caused by the very dynamic nature of the DOM API, and the solution to this should preferably be consistent with the solutions used elsewhere in the API. The reason it is in such a sorry state is that I just don't know what the right trade-offs are (yet). Of course I'd appreciate any input on this.

from bs-webapi-incubator.

jmorrell avatar jmorrell commented on May 31, 2024

Thoughts as a beginner:

MouseEvent.fromEvent

This suffers from low-discoverability and awkwardness. If I find this option and understand that I can use it to convert types, I now have an option type that I have to deal with. This all feels silly when I know good and well that I have a FooEvent. Clearly this type nonsense isn't worth the frustration.

polymorphic variants

iiuc this might look bad in the generated docs, but would actually function how a JS developer thinks. Code examples and hand-written docs can go a long way towards making this easy to get started.

ordinary variant

I don't understand this 🤷‍♂️

implement each and every on... property

If this means having a bunch of setOnMouseMove-like handlers that seems reasonable. While trying to figure out this issue I came across setOnClick and wished that I could have just used something like that.

this is just one of many issues caused by the very dynamic nature of the DOM API

It seems like there is a line to walk here between "mimics DOM API's and is familiar to JS devs" and "doesn't require hoops to jump through to type correctly". I don't have any intuition about what would feel idiomatic in Reason yet, so my question is: How would design an API to bind to events in a UI if you weren't trying to mimic the DOM's API?

from bs-webapi-incubator.

glennsl avatar glennsl commented on May 31, 2024

This suffers from low-discoverability and awkwardness.

Agreed.

Code examples and hand-written docs can go a long way towards making this easy to get started.

The API surface for the DOM is absolutely massive, and manually curated docs would be a huge additional burden. In the very very long term this might work, but in the short term it's not an option. Even just automatically generated html pages with lists of function signatures would be a big step up from what we have right now.

I don't understand this

An example would hopefully explain it better:

type eventType =
| MouseMove (mouseEvent => unit)
| ...

external addEventListener : string => ('a => unit) => unit = "" [@@bs.send.pipe: t];

let addEventListener (type_: eventType) (target: t) =
  switch type_ {
  | MouseMove callback => addEventListener "mousemove" callback target
  | ...
  }

It might also be possible using a GADT:

type 'a eventType =
| MouseMove : mouseEvent eventType
| ...

external addEventListener : string => ('a => unit) => unit = "" [@@bs.send.pipe: t];

let addEventListener (type_: 'a eventType) (callback: 'a => unit) (target: t) =
  switch type_ {
  | MouseMove => addEventListener "mousemove" callback target
  | ...
  }

If this means having a bunch of setOnMouseMove-like handlers that seems reasonable.

It would. As I said it's a very error-prone API, so I'm hesitant to expose it at all, but it's a very convenient way of doing ad hoc bindings in your own project.

How would design an API to bind to events in a UI if you weren't trying to mimic the DOM's API?

That would depend more on the nature and structure of the actual events I think. The DOM events are structured hierarchically, but even the event objects themselves are so dynamic it's hard to type them correctly. The target property, for instance, will often refer to an object of a known type, but for events that bubble it might not.

An ergonomic and safe API is also not the only consideration, it should also be performant and lightweight. There's a desire to have these bindings be a relatively thin layer, upon which more ergonomic bindings can be built.

from bs-webapi-incubator.

glennsl avatar glennsl commented on May 31, 2024

Added the overloads described in my last comment. I have some further ideas to imrpveo the API too, but that involves changing the types that ship with bs-platform, and so needs some planning.

from bs-webapi-incubator.

Related Issues (20)

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.