yjbanov / butterfly

A web framework for Dart based on Flutter's widget model
Apache License 2.0
156 stars 13 forks source link

Proposed Redesign of HTML widgets #23

Closed jonahwilliams closed 6 years ago

jonahwilliams commented 7 years ago

I propose a redesign of the current HTML elements to better fit with the Flutter style of UIs, and to allow some optimization and shrinking of code for updating/rendering elements.

Current Design

This change isn't completely done yet, however if we convert the existing VirtualElementBuilders directly into flutter style widgets we get something like this

  new Div(
    children: [
      new Button(
       children: [
         new Text('Click me', style: new Style('....')
       ],
       eventListeners: {
          OnClick: (_) {},
       },
     ),
    ]
);

This requires us to have a ton more functionality than we need on each element (just like real HTML!). It also means more update code, and fewer opportunities to make things const.

Updated Design

Renderless Widget

Instead of each html element corresponding with a native element, we can create a new type of widget which only modifies it's children. (Let's not call them decorators since that is already a thing, maybe RenderlessWidget or something?). For example:

new Div(
  children: [
    new ClickArena(
      child: ....,
      onClick: (_) {}
   ),
  ],
);

Here ClickArena modifies it's child widget by attaching an event listener, or using a global event listener system.

Common attributes and styles as classes

By splitting common attributes, like alt. width, and height for <img> tags into named arguments we can make the widget trees more readable and efficient (and more easily constable). Style objects could instead be represented as specific kinds of Style (TextStyle, DefaultTextStyle a Renderless Widget).

new Button(
  child: const [
     const Text('Click Me', style: const TextStyle(color: Colors.red[500)),
  ],
);

Layout Widgets

I think we've already discussed and proposed this, but it goes along with the above. Instead of using style objects to set flex attributes, create Column, Flex and Container classes to do layout.

Element as an escape hatch

For cases where we have not yet created good widgets or for interop with custom elements, create a class called Element which allows you to manually set attributes and styles. Event Listeners should still be restricted I think.

yjbanov commented 7 years ago

This is a really cool idea! I like the partitioning into multiple domains, such as events, text style, layout, etc. Very few situations require all of these simultaneously. For example, few elements have events attached to them. It's pay-for-what-you-use both API-surface-wise and performance-wise (no need to diff events if none are used).

However, I wonder if Column, Row and Container should actually have an element. I expect in most cases if you want a column you don't need to customize the underlying element. We could still have "renderless" (yeah, let's bikeshed on the name a bit) ColumnLayout and RowLayout.

I also think it would be useful to distance the core widget set from barebones HTML elements. The expectations of modern apps are very high these days. Plain HTML elements aren't as useful as they used to be. They are mostly used for layout and decorations, and if we give enough of those primitives, that use-case goes away. What remains are interactions, and those are usually tightly specced out by designers and implemented by widget vendors. Routine access to CSS is more likely to cause bugs, sacrifice fidelity and hurt performance. Also, there seems to be enormous amounts of CSS in large apps. I think there are issues with code reuse.

jonahwilliams commented 7 years ago

In an application, I don't think there is a good argument for semantic elements like <section>, <article>, or <footer>. Nor do we need style elements like <b>, <i>. If we trim all of the fat, we have left are

In most of these cases it would make more sense to expose some composite of the underlying elements. For example, have a table widget which creates the necessary <th>, <td>, <tr> without needing the user to specify them. For the input element, expose each of the specific input types (checkbox, text, et cetera) instead of just an Input widget.

Regarding layout widgets, I am not sure of a good way to implement them without an underlying div and some css. But we certainly don't need to expose that element for modification.

yjbanov commented 7 years ago

we certainly don't need to expose that element for modification

That's an interesting point. Should the child somehow allow its element to be decorated?

BTW, which part of the stack reserves "decorator"?

jonahwilliams commented 7 years ago

It could be nothing but when I hear decorator I think of python/javascript decorators.

thosakwe commented 7 years ago

Not sure if this is 100% related, but I have a library that might help out here: https://github.com/thosakwe/html_builder

Instead of classes, though, builders are functions. Not sure how that might gel here:

div(
  c: [
    button(c: [
      text('Click me!')
    ])
  ]
);
yjbanov commented 7 years ago

@thosakwe looks interesting. I haven't thought about abbreviating parameters to get a more DSL-like look.

We currently decided to focus on semantics before we start tackling syntax. For example, we postponed our Dx idea, and this proposal will also kill the current DSL.

One thing we cannot predict right now is how much developers will be writing plain HTML. If we provide a rich enough library of layout and theming primitives, as well as out-of-the-box widgets, we may well see that developers never write bare <div> and <button>, but instead use Row, Column, Flex, MaterialButton and other rich widgets.

Kleak commented 7 years ago

Hey i have write a little library like that for angular Dart. I have seen you are looking for help so here i'm and i think butterfly is a cool experiment :)

yjbanov commented 7 years ago

@Kleak cool to see experimentation like this! Do you have any usage examples for your library?

Thanks for offering help! Would be great for us to exit this bootstrapping phase so we can parallelize work. However, if you would like to tackle anything do let us know. I think the best way is to create an issue so we can track who is doing what.

yjbanov commented 7 years ago

...and to kick off this process, I created and assigned an issue to myself :)

yjbanov commented 7 years ago

BTW, is this issue done with https://github.com/yjbanov/butterfly/pull/27 or is there more work to do?

jonahwilliams commented 7 years ago

I am working on one more PR to remove the current element/virtual elements and replace them with the correct Multichild, SingleChild, Node classes. Should be done sometime tonight.

Kleak commented 7 years ago

Awesome ! Will keep an eye on the issues tracker if there is some task i can handle and look the code more in depth to maybe create issue also.

I dont have example for now but it's on my todo ;) (Probably this week)

Kleak commented 7 years ago

For Column, Row, Flex, etc it will be preferable to use custom tag name like in angular like that when we inpect the html in devtools we can read it more easily

yjbanov commented 7 years ago

@Kleak I agree that these widgets need to be inspectable for great developer experience. Flutter-like DiagnosticPropertiesBuilder might be the way to go? I'm not quite sure that it has to take place in the browser devtools. Some reasons why:

I think a better approach might be something like Android Studio Hierarchy Viewer or React Developer Tools extension for Chrome. Ideally it would be a standalone desktop app that works with all browsers.

Kleak commented 7 years ago

Thanks for the clarification. It seems just devtools will not be enough. A standalone desktop app that connect itself to the butterfly dev server to get all the information about the app ?

yjbanov commented 7 years ago

A standalone desktop app that connect itself to the butterfly dev server to get all the information about the app?

Yep, but this won't happen any time soon, this being a side-project and having fairly big scope :)

Kleak commented 7 years ago

sure but more we are more work can be done i the same period of time :)