-
Notifications
You must be signed in to change notification settings - Fork 3
Home
Component library to declarative programming of UI in web app based on Dart language.
This is the first draft of the documentation. Please, assume it while you are reading it. If you miss something or some part is messy, please mention about it in issue #29 Documentation .
Tiles is a component-based UI library inspired by React library. As the port of the react react-dart was slow because of the life-cycle methods, which communicate from the JavaScript to Dart.
The information that Tiles is inspired by React can be quite useful because the great part of API is very similar. But naturally, there are differences.
For this first step of writing the docs, we will reference the React a lot.
There are 3 parts of basic API meant to be used by the user of the library:
-
Component
class, -
registerComponent
method, -
mountComponent
method and -
initTilesBrowserConfiguration
method.
The Component
class is the place, where all logic of the UI lives.
For example, the one todo in the todolist can be a Component
.
Its idea is highly inherited from the React library.
The Component
class is very huge an offer not so big API. It offers the life-cycle methods, props and children by default, need update stream, redraw function and require render function.
The full component API is documented in it's file component.dart
render
method is the most important gateway from the library to the component.
Render should say in the name of the component "What should I look like" with the meaning,
how the DOM under the component should be constructed.
It must return instance of the ComponentDescription
, or a list of them (List<ComponentDescription>
), otherwise the Tiles throw an exception, when it wants to render it.
We will introduce the ComponentDescription
concept in the registerComponent
part.
The basic example of the render method can be:
class HelloComponent extends Component {
/* ... */
List<ComponentDescription> render() {
return [
h1(children: "Hello world"),
div(children: [
p(children: "This is the hello component")
])
];
}
}
When this component is mounted to the com, it produces following markup(formatting added):
<h1> Hello world </h1>
<div>
<p> This is the hello component </p>
</div>
The every component receives some data from it's owner (inherited from react, will be documented later).
This first data type is represented by props
, which are the dynamic variable to enable the user of the library to pass any data he wants.
The second data type are children
, which represents "what my owner want me to render as children".
The component can, but don't have to use them.
This concept is inherited from the React, so for now, i will don't write about it more.
We inherited some life-cycle methods from the React library, but not all of them. Here is the list of supported life-cycle methods:
- constructor is a basic constructor of the class. It should have at least arguments for props, and children. This is the place, where the initial setting should ocure, where the initial state of the component should be created
- didMount notifies the component that it was mounted to the DOM. This is the place to start timers, start listening to some custom streams etc.
- willReceiveProps is the place, where the Tiles notifies the component that it will receive new props from the owner. Component can compare old props with the new one and make appropriate changes.
- bool shouldUpdate is a question for the component, if it wants to update in current situation. It is use for the optimization of the performance. When it returns false, it is not updated, and the part of the virual DOM under it is also not updated.
- didUpdate tells component, that all of the changes in it's structure was applied to the real DOM
- willUnmount give the component an information, that it will be removed from the DOM. This is the place for stoping timers, close streams...
When you call the redraw
method, the component will be updated when the first animation frame occurs.
The needUpdate
stream is used passing this information to the "higher structure".
To easy usage of the component is needed to register it.
For the registering of the component the ComponentFactory
is needed.
It is a function with two optional parameters, which returns new Component
.
The registerComponent
method will return the ComponentDescriptionFactory
, which is also a method, which will from the given named parameters (props, children, key, listeners) produce new ComponentDescription
.
This description describe the Component and is processed by the tiles when mounting to the DOM.
In this example, we will register the HelloComponent
from the previous example.
ComponentDescriptionFactory helloComponent = registerComponent(
({props, children}) => new HelloComponent(props, children) // ComponentFactory
);
This `ComponentDescriptionFactory is then used from the render method or to mount component to the element (next part).
Assume that you have registered the HelloComponent
component in a helloComponent
variable.
When you want to render it into the real DOM, you need to mount it to the element.
Element mountRoot = querySelector("#todo_list_container");
mountComponent(helloComponent(), mountRoot);
From this moment, the HelloComponent will live under the mountRoot. It will process the events, live it's live-cycel etc.
The initTilesBrowserConfiguration
method is necessary to be called one at the beginning of the rendering. As the tiles library is updating the real DOM on animationFrame
event, the first listener should be setted up sometime. This is the purpose of the initTilesBrowserConfiguration
method.
It should be called only once, because we don't want to "redraw" real DOM more then once on every animationFrame
.
You can add the event listeners for any component you want. The list of supported listeners is in the events.dart file.
You can attach the listener in the ComponentDescriptionFactory
by the listeners
argument.
It accepts a Map<String, Listener>
, when Listener
is a function with two arguments: bool EventListener(Component component, html.Event event)
.
An example of usage on the button is following:
class AnotherHelloComponent extends Component {
render() {
return div(children: [
"try click the button and look at the console",
button(
children: "Hello World",
listeners: {
"onClick": buttonClicked
}
)
])
}
buttonClicked(component, event) {
print("button clicked");
}
}
Events bubbles trought the virtual DOM. This bubbling can be stopped by returning false
from the listener function.
Sorry, this is only the first draft of some documentation, I hope it helps, it will be refined later.