localvoid / uix

[UNMAINTAINED] Dart Web UI library
BSD 2-Clause "Simplified" License
77 stars 4 forks source link

API #9

Open cgarciae opened 9 years ago

cgarciae commented 9 years ago

I've been exploring how to create view. I really like the way the react-dart project has simplified creating common elements. They create function with the names of common elements like this

VNode div ({Object key, String type, Map<String, String> attrs, Map<String, String>
style, List<String> classes, List<VNode> children, bool content: false})
  => new VNode.element('div', key: key, type: type, attrs: attrs, style: style, classes: classes,
                              children: children, content: content);

So you can create elements like this

updateRoot(
  vRoot()(
    div (attrs: {"width": "100"})(
      div()(
        "Hola $data"
      )
    )
  )
);

But that definition is too verbose.So there is this other option, create the tags as getters

VNode get div => new VNode.element('div');
VNode get root => new VNode.root();

and try to write code by accessing the fields using cascade operators

    updateRoot (
      root (
        (div..attrs.addAll({"width": "100"}))(
          div ("Hola $data")
        )
      )
    );

The downside is that you need to wrap things in parenthesis if you want to access fields (like in the first div). So I propose a solution, change the name of each field and create a methods that sets it with the old name, also have those methods return this so you could chain them

class VNode {
  ...
  VNode attrs (Map attributes) => this.._attrs.addAll (attributes);
  VNode classes (List newClasses) => this.._classes.addAll (newClasses);
}

That way you could write code like this

    updateRoot (
      root (
        div.attrs({"width": "100"}).classes(['big', 'words'])(
          div ("Hola $data")
        )
      )
    );

To me this last version look really clean, very html like, a little bit less parenthesis,

BTW: why is there an updateRoot and updateView? Are there cases where you dont call both?

localvoid commented 9 years ago

I've tried similar approach in liquid library, and I think that it was a mistake. For example, creating functions with names like a, or i just feels like I am doing something really bad. It is possible for the user of the library to import all this functions into namespace like vdom, but then it won't be worth it. In uix library I've tried to make the library as simple as possible.

BTW: why is there an updateRoot and updateView? Are there cases where you dont call both?

In canvas example, updateView doesn't use updateRoot, it draws to canvas. In mount example there is a progressive enhancement with multiple calls to updateRoot. In readDom example, there are updateRoot -> read from dom -> updateRoot chain.

I even thought about moving all virtual dom methods out of Component class and just make it as a mixin, but most of the time Components will use virtual dom api, so I just made it simple.

cgarciae commented 9 years ago

@localvoid I've never seen a 3rd party React tutorial that doesn't use JSX, that tell you that people wan't something similar to html for design. I think readability should be a feature. Also, I don't see a problem with functions named i or a, those names are extremely clear in this context.

localvoid commented 9 years ago

Variables like i are commonly used in for-loops. area, map, input, etc are likely to be used as Component properties, or vars inside of updateView method. So, now everyone starts to import vdom functions into some namespace like vdom just to make everything consistent, and now we have vdom.i() vs vElement('i').

vElement also more flexible: vElement(isOrdered ? 'ol' : 'ul'). And it doesn't require creating any wrappers for custom elements.

And now we need to make virtual nodes for components to be consistent with elements, so we start creating functions that create this vnodes, but how we should name it? vMyComponent? Should we import all our ui code into the same namespace as all vdom functions?

In the end it will be really messy, I don't want to repeat the same mistake that I've made in liquid library. There is no difference between vdom.i() and vElement('i'), it is more like "tab vs spaces". Code readability comes from "declarative" approach.

I also don't want to pretend that virtual dom in uix library is like a "html", it is a tool for dom mutations, and developers should understand things like keys etc, otherwise they will lose internal state. It is also not one-to-one mapping to the real dom, it is possible to control classes, styles, attributes outside of components with vComponent node and inside with vRoot node.

cgarciae commented 9 years ago

Ok, I dont see issue with variable names. On the other hand declaring by string is error prone, lacks autocompletion and takes more time. If this is your html, seeing names like vComponent and vElement everywhere just gets in your way.

localvoid commented 9 years ago

If you prefer this way to create virtual nodes, you can always create additional library that will have such helpers. I really don't like this approach, especially with getters. And addAll() for assigning classes, attrs, etc will be really bad for performance.

Typical react-like component has 1-3 level dom depth, so saving 3-5 chars per virtual node creation is actually not important, and from my experience, I am spending significantly more time on other things, dealing with dom structure is not a problem.

I am actually planning to get rid of input components, css transition container, and move them to separate libraries. uix library will contain scheduler, virtual dom diff/patch and component base class, everything else should be created as separate libraries.

tosh commented 9 years ago

imho it sounds wise to keep uix simple and clean and have more opinionated things in separate libraries. if people prefer a more terse DSL or something like jsx it is possible to build it on top/orthogonal to uix.

This way uix stays fairly stable and has a well defined scope as feature set and we all can experiment with various ways to leverage uix while building on common ground.

cgarciae commented 9 years ago

Once I have them, I will publish a shortcut library ;)

On Tue, Apr 28, 2015, 02:32 Thomas Schranz notifications@github.com wrote:

imho it sounds wise to keep uix simple and clean and have more opinionated things in separate libraries. if people prefer a more terse DSL or something like jsx it is possible to build it on top/orthogonal to uix.

This way uix stays fairly stable and has a well defined scope as feature set and we all can experiment with various ways to leverage uix while building on common ground.

— Reply to this email directly or view it on GitHub https://github.com/localvoid/uix/issues/9#issuecomment-96959948.