Calling Elvis
Is anybody home? The Evlis Book mainly talks about the usage of elvis, here is our roadmap, come and join us !~
Help Wanted
- A static http/websocket development server #16
- Documentation of ElvisJS #65
- A Markdown parser using ElvisJS #66
- Optimize the State machine #67
Getting Started
# Install elvis package manager
$ cargo install epm
# New your awesome-app
$ epm new my-awesome-app
# Start development server
$ cd my-awesome-app && epm dev
[INFO warp::server] listening on http://0.0.0.0:3000
Hello, World!
#![allow(unused)] fn main() { //! src/lib.rs use elvis::{ prelude::*, widgets::{layouts::Center, Text}, }; #[page] struct Index; impl LifeCycle for Index { fn create(&self) -> Node { Center::with(Text::with("Hello, World!")).into() } } }
Examples
LICENSE
Heartbreak Hotel.
Arch
This chapter is about the arch of ElvisJS.
backend
This crate is a backend which can compile elvis code just in time, for example, it compiles the rust code into wasm, and starts a web server to serve our web APP.
core
The core library abstracts the UI without invoking into any platform.
We don't need to know how it works if you just want to develop Apps using ElvisJS, because the elvis library provides all we need in the core library.
Node
The common UI of ElvisJS are composed with nodes which are defined in this core library, just the frame and transform stuffs.
UI
Attribute && Class
Attribute and Class are defined in this library as well, both of them are served for
the Node
, attribute controls the features of Node, and the class affect on the style
of Node.
Values
All static values are defined in this library, for example, Color
, Unit
.
Layout
Finally, we are reaching the layout part. The difference of ElvisJS and other UI library in rust/wasm is ElvisJS provides UI itself, not just give you guys a parser parsing rust to Javascript or html.
The layout part is only defined in the core library, for example, the web library is just a re-export of the layout part of this core library, migrating the ElvisJS UI into browser.
Lifecycle
The lifecycle of ElvisJS defines like
LifeCycle | Description |
---|---|
Create | Triggers while creating the component in node tree |
Render | Triggers while rendering the component in node tree |
Update | Triggers when the state machine changes |
Drop | Triggers while droping the component |
State machine
State machine of Elvisjs equipped for user-defined components, the fields of the struct are the storage of the state machine, which we can modify in gestures.
derive
This is a proc-macro crate for constructing our elvis code, named elvis-derive. It can help us writing Elvis Apps easily.
Don't worry about the usage of this repo, you can see how to master them in our examples.
epm
This the package manager for ElvisJS. You can generate elvis App using this repo, yep,
after cargo install epm
.
support
This is a inside proc-macro crate, only for development, you can find the source code here if you are interested in it.
web
This is the web interface of ElvisJS, like the core crate, it is contained in the elvis crate, don't worry about how to use this unless you want to hack.
Benchmark
A counter App is the target where elvis tests runs.
/* PATH='counter/pages/index.js' */
import { Center, Text, StatefulWidget } from "calling-elvis";
class Counter extends StatefulWidget {
state = {
hello: "Is anybody home?"
}
create() {
let start = new Date().getTime();
for (let i = 0; i < 100000000; i++) {
this.state.hello = i.toString();
}
let end = new Date().getTime();
console.log((end - start) + "ms");
}
render() {
return Center(
Text(this.state.hello, {
bold: true,
italic: true,
size: 6,
})
);
}
update() {
console.log("update...");
}
dispose() {
console.log("dispose...");
}
}
export default Counter;
# PATH='counter/'
yarn dev
Model | Processor | Memory |
---|---|---|
mbp.Catalina.17.13-inch | 2.3 GHz Dual-Core Intel Core i5 | 16 GB 2133 MHz LPDDR3 |
DOM Update
library | 10,000 | 100,000 | 1,000,000 | 10,000,000 | 100,000,000 |
---|---|---|---|---|---|
elvis | ~1ms | ~10ms | ~100ms | ~900ms | ~8s |
react | ~35ms | ~125ms | ~830ms | ~8000ms | broken |
vue | ~7ms | ~40ms | ~280ms | ~3000ms | ~26s |
Bundle Size
library | size |
---|---|
elvis | 432kb |
react | 484kb |
vue | 592kb |
Library
Elvis
currently contains:
Widgets
Widgets coming as they are!
Elvis
just provides Image
and Text
for now, we've got apis to compose new Widget
s in rust api, join us if you like calling Elvis.
#![allow(unused)] fn main() { /// Elvis' Attribute is cool. /// /// The no-cool part is, Elvis has a big Attributes Enum system, /// it's more responsible to use enum than chars. pub struct Attribute { key: Attributes, value: AttributeValues, } /// Abstract ElvisElement pub trait ElvisElement { // give birth to a new life fn append(&mut self); // deserialize html string to ElvisElement fn de(s: String) -> ElvisElement; // call her/his father fn father(&self) -> ElvisElement; // if you don't have a girlfriend, new one. fn new<T>() -> T; // serlalize ElvisElement to html string fn ser(&self) -> String; } /// Love is All you Need! /// /// Speaking easily, you don't need to write the trait above, /// Elvis has a proc-macro to impl the trait defaultly, /// just paint your child. #[derive(ElvisElement)] pub struct MyElement { css: String, tag: String, attrs: Vec<Attribute>, child: Arc<AsRef<ElvisElement>>, } }
Javascript
It's quite intresting dressing widgets up for a new face, we can do anything changing Elvis we want in Javascript, it depends on if you have the power to save the world, as we know, you are the one.
Image
/* Image */
import { Center, Elvis, Text, Image } from "calling-elvis";
// Generate a `Image`
const myImage = Image({
src: "https://images-assets.nasa.gov/image/S65-34635/S65-34635~orig.jpg",
child: Text("hallo, spaceboy!"),
});
Elvis.call(Center(myImage));
If you don't want Image
playing in background anonymously, just remove the child field.
Declaration:
function Image({ src: string, child: Widget, }): Widget;
Text
/* Text */
import { Center, Colors, Elvis, Text } from "calling-elvis";
Elvis.call(
Center(
Text("Calling Elvis", {
bold: true,
color: Colors.PinkAccent(),
italic: true,
size: 42.0,
weight: 700,
height: 20,
stretch: 100,
}),
),
);
Text
might be the most popular spider from Mars, Does it know the Great Ziggy Stardust
?
Declaration:
function Text(text: string, { bold: boolean, color: Colors, italic: boolean, size: number, // rem weight: number, // rem height: number, // rem stretch: number, // percent }): Widget;
DOM
Like the other UI libraries, webassemblly Elvis arms a Virtual-DOM, too.
import { Center, Elvis, GestureDetector, StatefulWidget, Text } from "calling-elvis";
class MyState extends StatefulWidget {
state = {
count: 0,
}
create() {
console.log("The first step is creating the dom.");
}
update() {
console.log("Then we can update it, just like what you saw.");
}
render() {
return Center(
GestureDetector(
Text("I'm a Elvis fans."),
onTap: () => this.setState({
count: this.count + 1
});
),
);
}
dispose() {
console.log("Don't be crue, if you want to drop me.");
}
}
I won't tell you that Elvis
is not only a React
fan but also a Flutter
fan, and you'll never know he is a Emacs
fan.
LifeCycle
Already knew you care about lifecycles, Elvis will never force you to recite 11 or more methods, Elvis just got 3, and it is enough ; )
Furthermore, to be serious, we don't recommend you to write big projects such as facebook
, reddit
, or twitter
calling Elvis, Elvis
is under Proof-of-Concept for now, and...you know, we strongly recommend you to use Elvis building your persenol website, make the web better, more interesting, awesome as it has never been 🌈
And if you are building a rocky start-up project, believe me, CALLING ELVIS, and the force will be with you!
Life Story, Love and Glory.
Diff
Elvis' diff algorithm is quite simple flying with wasm, we compare the new node and the old one using dps, and then patch the updates to the old one.
Patch
Elvis prefers to cure the naughty node's father node, if there are complex changes inside it, for Example:
<father :="I'm the naughty nodes' father">
<naughty>Up</naughty>
<naughty>Side</naughty>
<naughty>Down</naughty>
</father>
Now we upside down the Up
, Side
, Down
List:
<father :="plz don't make me heartbreak for twice.">
<naughty>Down</naughty>
<naughty>Side</naughty>
<naughty>Up</naughty>
</father>
Elvis with not trying to swap <li>Up</li>
and <li>Down</li>
, it will operate DOM twice over, we just replace the whole <ol>...</ol>
for once.
Events
Note: In progress.
Follows MDN docs Events
Events
share properties to State
, kind like a third-part plugin in Elvis
, it implelements both in rust
and typescript
.
Javascript
/* Events */
import { Component, Elvis, Events } from "calling-elvis";
const { Text } = Elvis;
class myClickAbleText extends State {
state = {
msg: "",
}
consturstor(msg: string) {
this.msg = msg;
}
click() {
window.alert(`{}, roger that!`);
}
render() {
return Text("Click me plz.");
}
}
Elvis Events
are outside of native components, we writing them straight just like writing lifecycles
. Elvis
strongly recommands our folks writing persnal components even publishing them to github
.
Rust
#![allow(unused)] fn main() { pub enum Events { Cancel, Error, Scroll, Select, Show, Wheel, // Clipborad events Copy, Cut, Paste, // Composition events CompositionEnd, CompositionStart, CompositionUpdate, // Focus events Blur, Focus, Focusin, Focusout, // Fullscreen events KeyDown, KeyPress, KeyUp, // Mouse events AuxClick, Click, ContextMenu, DbClick, MouseDown, MouseEnter, MouseLeave, MouseMove, MouseOut, MouseOver, MouseUp, WebkitMouseForceChanged, WebkitMouseForceDown, WebkitMouseForceWillBegin, WebkitMouseForceUp, // Touch events, TouchCancel, TouchEnd, TouchMove, TouchStart } }
Events enum list all events in MDN events, the implementation in rust depends on gloo
.
Gestures
Note: In Progress.
Event
and Gesture
are out of wasm, this is not cool, but still awesome, Elvis
implements these two trouble maker in Typescript
, because wasm-bindgen
doesn't support passing javascript Object
to rust for now, BUT, it will be totally cool one day.
GestureDetector
#![allow(unused)] fn main() { pub trait GestureDetector { fn on_double_tap(e: Event); fn on_force_press_end(e: Event); fn on_force_press_peak(e: Event); fn on_force_press_start(e: Event); fn on_force_press_update(e: Event); fn on_horizontal_drag_cancel(e: Event); fn on_horizontal_drag_down(e: Event); fn on_horizontal_drag_end(e: Event); fn on_horizontal_drag_start(e: Event); fn on_horizontal_drag_update(e: Event); fn on_long_press(e: Event); fn on_long_press_end(e: Event); fn on_long_press_move_update(e: Event); fn on_long_press_start(e: Event); fn on_long_press_up(e: Event); fn on_pan_cancel(e: Event); fn on_pan_down(e: Event); fn on_pan_end(e: Event); fn on_pan_start(e: Event); fn on_pan_update(e: Event); fn on_scale_end(e: Event); fn on_scale_start(e: Event); fn on_scale_update(e: Event); fn on_secondary_tap_cancel(e: Event); fn on_secondary_tap_down(e: Event); fn on_secondary_tap_up(e: Event); fn on_vertical_drag_cancel(e: Event); fn on_vertical_drag_down(e: Event); fn on_vertical_drag_end(e: Event); fn on_vertical_drag_start(e: Event); fn on_vertical_drag_update(e: Event); } }
Are we still cool now?
Gesture
in calling-elvis
implements with typescript, but elvis
still keeps these apis, so we still can rust the web happily with Elvis
without confuse.
Layout
Follows MDN doc CSS Layout.
Widgets 📦
Elvis Layout mainly contains Flex
and Grid
, btw, Elvis offerrs two basic widgets Container
and SizedBox
for simple usages.
Container
/* Container */
import { Container, Colors, Elvis, Alignments } from "calling-elvis";
// Generate a `Container`
const myContainer = Container(
Text("Where is my AJ-1?"), {
align: Alignments.Center,
color: Colors.Black(),
height: 42,
margin: 10,
padding: 10,
width: 42,
});
Elvis.call(myContainer);
The Alignments
enum is from Flex
, to be honest, Container
component is a part of Flex
family, but he is too brilliant to stay in Flex
family, Layout
calls him.
Declaraction:
function Container(child: Widget, { align: Alignments, color: Colors, height: number, // rem margin: number, // rem padding: number, // rem width: number, // rem }): Widget;
List
/* List */
import { Elvis, List, Text } from "calling-elvis";
// Generate a `List`
let myList = List([
Text("poor-orphan-1"),
Text("poor-orphan-2"),
Text("poor-orphan-3"),
]);
Elvis.call(myList);
(Sorry about that), List
is a set of poor orphan children, they don't have any style, just blowing in the wind.
Declaraction:
function List(widgets: Widget[]): Widget;
SizedBox
/* SizedBox */
import { Elvis, SizedBox, Text } from "calling-elvis";
// Generate a `SizedBox`
const mySizedBox = SizedBox(
Text("My SizedBox"), {
height: 42,
width: 42,
});
Elvis.call(mySizedBox);
SizedBox
just has width
and height
two arguments, we use this component to take some white space usually.
Declaraction:
function SizedBox(widget: Widget, { height: number, // rem width: number, // rem }): Widget;
Flex
Follows MDN doc CSS Flexible Box Layout
Widgets 📦
The very basic core of Flex
Layout widgets is called Flex
, unfortunatly, it contains almost all css flex properties, no easy to use, that's why elvis composes some newbie components as well.
Align
/* Align */
import { Align, Alignments, Elvis, Text } from "calling-elvis";
// Generate an `Align`
let myAlign = Align(
Text("Align Elvis"), {
align: Alignments.Center,
});
Elvis.call(myAlign);
Align
inherits the core usage of Alignment
, it's quite simple, just one property.
Declaration:
function Align( child: Widget, { align: Alignments, }): Widget;
Center
/* Center */
import { Center, Elvis, Text } from "calling-elvis";
// Generate an `Center`
let myCenter = Center(
Text("My website only have a line of chars 🦀 "),
);
Elvis.call(myCenter);
Center
is a very nice widget, if your website only have a line of chars, use it!
Declaration:
function Center(child: Widget): Widget;
Col
/* Col */
import { Col, Elvis, Text } from "calling-elvis";
// Generate a `Col`
const myCol = Col([
Text("All is above you all is sky"),
Text("All is behind you all is sea"),
]);
Elvis.call(myCol);
Col
towards column, the typical flow in html, with flexible enhance.
Declaration:
function Col(widgets: Widget[]): Widget;
Flex
/* Flex */
import { Elvis, Flex, List, Text } from "calling-elvis";
const myFlex = Flex(
List([
Text("hi, I'm the Lunatic Widget's child No.1"),
Text("hi, I'm the Lunatic widget's child No.2"),
Text("hi, I'm the Lunatic Widget's child No.3"),
)], {
align: Alignments.Center,
basis: FlexBasis.Fill(),
direction: FlexDirection.ColumnReverse,
grow: 1,
order: 1,
shrink: 1,
wrap: true,
});
Elvis.call(myFlex);
This is the Lunatic Widget to Ground Control, I'm stepping throw the Window
.
Declaration:
function Flex(widget: Widget, { align: Alignments, basis: FlexBasis, direction: FlexDirection, grow: number, // no unit order: number, // no unit shrink: number, // no unit wrap: boolean, }): Widget;
Row
/* Row */
import { Elvis, Row, Text, } from "calling-elvis";
// Generate a `Row`
let myRow = Row([
Text("I'm Wrong"),
Text("I'm Right"),
]);
Elvis.call(myRow);
Both Col
and Row
are using flex-start
, if you want to reverse the children of them, better to work on the list order.
Declaration:
function Row(widgets: Widget[]): Widget;
Enums 🍩
Elvis Layout
Aligns follows the MDN doc [CSS Box Alignment][2], but simplify it into a enum Aligment
here, Alignment
is used by all Flex
components and Container
in Elvis.
Alignment
Here is the Alignment
defination in rust source code.
#![allow(unused)] fn main() { /// Magical Alignment pub enum Alignment { BottomCenter, BottomLeft, BottomRight, Center, CenterLeft, CenterRight, TopCenter, TopLeft, TopRight, } }
FlexBasis
#![allow(unused)] fn main() { pub enum FlexBasis { Fill, MaxContent, MinContent, FitContent, Number(Unit), // Rem } }
Well, lunatic FlexBasis
in Rust source code.
FlexDirection
#![allow(unused)] fn main() { pub enum FlexDirection { Column, ColumnReverse, Row, RowReverse, } }
Lunatic FlexDirection
, you know it.
Grid
Follows MDN doc Grids.
Here is the Grid
section, Just let Elvis show you how Grid
Grid.
Grid
/* Grid */
import { Grid, GridAuto, GridFlow, GridTemplate, Elvis, Text } from "calling-elvis";
// Generate an `Grid`
const myGrid = Grid(
List(
Text("Mercury"),
Text("Venus"),
Text("Earth"),
Text("Mars"),
Text("Jupiter"),
Text("Saturn"),
Text("Uranus"),
Text("Neptune"),
Text("Pluto"),
), {
col: Grid.Auto(),
col_gap: 1,
flow: GridFlow.Column(),
row: Grid.Auto(),
row_gap: 1,
template_col: GridTemplate.Inherit(),
template_row: GridTemplate.Inherit(),
});
Elvis.call(mySizedBox);
Take it ease, only one Grid
widget in Elvis.
/* Grid */
import { Grid, Elvis, List, Text } from "calling-elvis";
// Generate an `Grid`
const myGrid = Grid(
List(
Text("Mercury"),
Text("Venus"),
Text("Earth"),
Text("Mars"),
Text("Jupiter"),
Text("Saturn"),
Text("Uranus"),
Text("Neptune"),
Text("Pluto"),
),
);
Elvis.call(myGrid);
Grid
is quite complex in some way, usually, we just Grid
our contains.
Declaration
function Grid(widget: Widget, { col: GridAuto, col_gap: number, // Rem flow: GridFlow, row: GridAuto, row_gap: number, // Rem template_col: GridTemplate, template_row: GridTemplate, }): Widget;
Enums 🍩
Grid Grid
is hard to pronounce, most of time we don't need to do this.
GridAuto
#![allow(unused)] fn main() { pub enum GridAuto { Auto, Fixed(Unit), Inherit, Initial, MaxContent, MinContent, MinMax(Unit, Unit), Plain(Vec<Unit>), Unset, } }
GridAuto
affect the width of Grid children, and the Auto
choice use the minmax
function in css, if doesn't pass the second argument, it will be auto
in meaning.
GridFlow
#![allow(unused)] fn main() { pub enum GridFlow { Column, Row, Dense, ColumnDense, RowDense, Inherit, Initial, Unset, } }
GridFlow::Column
by default.
GridTemplate
#![allow(unused)] fn main() { pub enum GridTemplate { FitContent(Unit), Inherit, Initial, MinMax(Unit, Unit), None, Plain(Vec<Unit>), Repeat(i32, Unit), SubGrid, Unset, } }
In the Plain
choice, Vec
's length will be the column count of grid, and every Unit
is the width of each column, Repeat
just make this easier, every child are in the same width.
MultiColumn
Follows MDN doc Multiple-column layout.
The very easy way to layout our pages, maybe fantastic in the old web, it means, the true web, I like it.
MultiColumn
/* MultiColumn */
import { Colors, Elvis, MultiColumn, MultiColumnLineStyle, Text } from "calling-elvis";
// Generate an `MultiColumn`
const myMultiColumn = MultiColumn(
List(
Text("Mercury"),
Text("Venus"),
Text("Earth"),
Text("Mars"),
Text("Jupiter"),
Text("Saturn"),
Text("Uranus"),
Text("Neptune"),
Text("Pluto"),
), {
color: Colors.Black(),
count: 3,
gap: 20,
style: MultiColumnLineStyle.Groove,
});
Elvis.call(mySizedBox);
Homework: code a New York Times.
Declaration
function MultiColumn(
widget: Widget, {
color: Colors,
count: number, // no unit
gap: number, // Rem
style: MultiColumnLineStyle,
}): Widget;
Enums 🍩
The style of MultiColumnLine
.
MultiColumnLineStyle
#![allow(unused)] fn main() { pub enum MultiColumnLineStyle { None, Hidden, Dotted, Dashed, Solid, Double, Groove, Ridge, Inset, OutSet } }
If I were you, I will choose MultiColumnStyle.Groove
, don't ask why.
Router
/* Entry */
import { Elvis, Router } from "calling-elvis";
import { Africa, America, Asia, Europe, Oceania } from "./map";
new Elvis({
home: Oceania,
routes: {
"africa": Africa,
"america": America,
"asia": Asia,
"europe": Europe,
"oceania": Oceania,
},
})
A ship got a Navigator
, we call it an App.
TODO*
We generate our routes in the entry of our Apps usually, Elvis
has inner url parser in the navigator process, both url parameters and object style arguments are supported, so if we want to fly to the Mars, just do it.
Values
Values
might be the most instresting part in Elvis, it focus on the design of our art.
Most of Elvis
widgets have enum properties, instead of writing them in plain text, it terms to 'less thinking', free as a bird, free as in freedom.
Homework
Paint out the Starry Starry Night, Shell
we?
Color
Follows MDN doc CSS Color Value
#![allow(unused)] fn main() { pub enum Colors { RGBA(i32, i32, i32, f64), Hex(String), HSL(Unit, i32, i32), Plain(String), Amber, AmberAccent, Black, Blue, BlueAccent, BlueGrey, Brown, Cyan, CyanAccent, DeepOrange, DeepOrangeAccent, DeepPurple, DeepPurpleAccent, Green, GreenAccent, Grey, Indigo, IndigoAccent, LightBlue, LightBlueAccent, LightGreen, LightGreenAccent, Lime, LimeAccent, Orange, OrangeAccent, Pink, PinkAccent, Purple, PurpleAccent, Red, RedAccent, Teal, TealAccent, Transparent, White, Yellow, YellowAccent, } }
So many colors...well, the Colors
above is Elvis' color system.
Unit
Follows CSS Values 3 drafted in csswg.org.
#![allow(unused)] fn main() { pub enum Unit { Ch(f64), Cm(f64), Dpi(f64), Dpcm(f64), Dppx(f64), Em(f64), Fr(f64), In(f64) Mm(f64), Pc(f64), Pt(f64), Px(f64), Q(f64), Rem(f64), Vh(f64), Vmax(f64), Vmin(f64), Vw(f64), } }
If we don't use Unit.X()
in number field, Elvis will choose Unit.Px
by default.
Absolute Lengths
unit | name | equivalence |
---|---|---|
cm | centermeters | 1cm = 96px/2.54 |
mm | millimeters | 1mm == 1/10th of 1cm |
Q | quarter-millimeters | 1Q = 1/40th of 1cm |
in | inches | 1in = 2.54cm = 96px |
pc | picas | 1pc = 1/6th of 1in |
pt | points | 1pt = 1/72th of 1in |
px | pixels | 1px = 1/96th of 1in |
Relative Lengths
unit | relative to |
---|---|
em | font size of element |
ex | x-height of element's font |
ch | width of the "0" (ZERO, U+0030) glyph in the element’s font |
rem | font size of the root element |
vw | 1% of viewport’s width |
vh | 1% of viewport’s height |
vmin | 1% of viewport’s smaller dimension |
vmax | 1% of viewport’s larger dimension |
Others
unit | represents |
---|---|
dpi | Dots per inch |
dpcm | Dots per centmeter |
dppx | Dots per px unit |
fr | This unit represents one fraction of the available space in the grid container. |
Tutorial
Well this is an official tutorial for Elvis
.
Installation
Use create-elvis-app
yarn create elvis-app
Use create-elvis-app
to generate elvis structure directly.
Use elvis-cli
# create directly
mkdir my-awesome-app && cd my-awesome-app
# add elvis-cli
yarn global add elvis-cli
# add elvis library
yarn add calling-elvis
# elvis-cli will generate pages defaultly
elvis dev
Starting manually
# create directly
mkdir my-awesome-app && cd my-awesome-app
# add elvis library
yarn add calling-elvis
/* router */
import { Elvis } from "calling-elvis";
import Home from "./home";
new Elvis({
home: Index(),
}).calling();
/* home */
import { Center, Text } from "calling-elvis";
const Home = () => Center(
Text("Calling Elvis!")
);
export default Home;
Starting Rustly
Checkout elvis' rust doc
Widgets
Single Widget
Elvis has StatefulWidget
and Widget
, usually, StatefulWidget
composed by class
and Widget
composed by variable
or function
.
StatefulWidget
class MyWidget extends StatefulWidget {
state = {
intro: "Is anybody home?",
}
render() {
return Center(
Text(this.state.intro),
);
}
create() {
console.log("create...");
this.state.intro = "Roll up for the magical mystery tour!";
}
update() {
console.log("update...");
}
dispose() {
console.log("dispose...");
}
}
Widget
// for variable
const myWidget = Center(Text("This is a line of chars"));
// for function
const myWidget = (line: string) => Center(Text(line));
Complex Widgets
We got some widgets made by our selvies sometimes.
class Child extends StatefulWidget {
state = {
name: "",
}
constructor(name: string) {
this.state.name = name;
}
render() {
return Text("My name is" + this.state.name);
}
}
Wrong example: Do not
new
Widget inside widgets, unless you want to pass props to it.class Parent extends StatefulWidget { render() { return Center(new Child("Elvis")); } }
If you did this, the
Child
widget will re-render everytime the parent widget changes, cause everyStatefulWidget
got a reflectpointer
in wasm, each of them gots its own widget tree and stylesheet.
class Parent extends StatefulWidget {
widgets = {
child: new Child("Elvis"),
}
render() {
return Center(this.widgets.child);
}
}
class Parent extends StatefulWidget {
state = {
name: "Elvis",
}
render() {
return Center(new Child(this.state.name));
}
}
Community
Contribute
There are some basic tips for someone who wants to contribute to evlis.
Firstly, welcome to post any questions about evlis via Github Issue, Email, etc. We will give you reaction as soon as possible.
Make A Change
-
Clone the repository on your local machine.
When contributing to an open source project using GIT, you will have a copy or “clone” of the source code repository in your local development environment.Here, you can make your changes and commit them locally to create a revision history, allowing changes to be tracked and easily rolled back if required.
$ git clone https://github.com/elvisjs/elvis.git
-
Build the source
Evlis is implemented purely in Rust, So, please make sure you have installed Rust before made contributions. There is not specific Rust version requirement, we recommend you to fetch the latest Rust version.
Once you have installed Rust, type the following in the terminal to start compiling:
$ cd elvis $ cargo build
The resulting binary can be found in
evlis/target/debug
.
Raising A Pull Request
Once you feel satisfied with the changes, you can raise a pull request on Github.
Our maintainer will then approve the changes or request some changes before it get merged.
Happy contributions!