Giter Site home page Giter Site logo

ithril's Introduction

ithril

Build Status

Mithril 1.1.1 for Haxe.

Ithril uses Haxe macros to transpile Jade/Pug like templates into Mithril hyperscript.

Template Syntax

Mithril views are declared in a class that extends ithril.Component or implements ithril.IthrilView. The declaration must be inside [brackets] marked with the @m meta.

import ithril.*;

class MyComponent extends Component {
    public override function view (vnode:Vnode) @m[
    	(div.intro)
    		(ul)
    			(li > 'Some')
    			(li > 'List items')
    		(ul.another-list)
    			(vnode.attrs.list => item)
    				(li > item)
    		(form)
    			(input[type="text"] (value = "Text value", onfocus = focus))
    			(input[type="checkbox"][required]) ['Check this']
    ];
}

class Views implements IthrilView {
    public function view1(vnode:Vnode) @m[
        (div > 'view one')
            (MyComponent(list=['item one', 'item two', 'item three']))
    ]
    
    public function view2(vnode:Vnode) @m[
        (div > 'view two')
            (MyComponent(list=['apples', 'oranges', 'bananas']))
    ]}
}

Elements

Any html element can be expressed in parentheses:

(img)

CSS classes can be set using the . operator:

(img.my-class-name.my-other-class-name)

An element id can be set with the + operator (as # wouldn't be valid haxe syntax):

(img+my-id)

Attributes can be used inside the selector:

(img[src="img.jpg"])

Attributes can also be expressed separately:

(img (src="img.jpg", alt=""))
(img ({src: "img.jpg", alt: ""}))
(img (aFunctionCallReturningAttributes()))

Children

A shortcut for defining one child:

(h1 > 'My title')

More than one child can simply be nested by using indentation:

    (nav)
    	(ul.links)
    		(li)
    			(a[href="http://haxe.org"] > 'Haxe')
    		(li)
    			(a[href="http://github.com"] > 'Github')

Inline expressions

Any expression can be used inside brackets:

(h1)
	['A string for example']
(button)
	[this.buttonLabel]
(div)
    [{
        var blockExpression = "is Ok";
        return blockExpression;
    }]
(div)
    [{
        return true ? @m[
            (div > 'this works too')
        ] : @m [ ]
    }]

Conditionals

If/else can be used inside templates:

($if (bigTitle))
	(h1 > 'Big')
($else)
	(h2 > 'Not that big')

For loop

(link in links)
	(a (href=link.url, target='_blank') > link.title)

Map

Following syntax can be used for any object (in this case links) with a map method:

(links => link)
	(a (href=link.url, target='_blank') > link.title)

Trusted HTML

Embedding javascript or CSS assets requires marking content as trusted so it is not automatically escaped. Use the @trust meta:

(style > @trust css)
(script)
    [@trust javascript]

Components

Custom components can be created by extending ithril.Component. A component can then be used in a view like any other element:

class Hello extends Component {
    public override function view (vnode:Vnode) @m[
    	(div.component > 'Hello ' + vnode.attrs.name)
    ];
}

class World implements IthrilView {
    public function helloView(vnode:Vnode) @m[
            (Hello(name='World'))
    ]
}

Children

Children of a Component can be accessed via vnode.children:

class List extends Component {
	public function view(vnode:Vnode) [
		(ul)
			(vnode.children => child)
				(li > child)
	];
}

Which can be used like this:

(List)
	(span > 'A')
	(span > 'B')
	(span > 'C')

And would output:

<ul>
	<li><span>A</span></li>
	<li><span>B</span></li>
	<li><span>C</span></li>
</ul>

Lifecycle

Mithril creates, reuses, and destroys components as specified by it's diffing algorithm. The lifecycle of a Component can be observed by overriding these methods:

	public function oninit(vnode:Vnode) {}
	public function oncreate(vnode:Vnode) {}
	public function onupdate(vnode:Vnode) {}
	public function onbeforeremove(vnode:Vnode) {}
	public function onremove(vnode:Vnode) {}
	public function onbeforeupdate(vnode:Vnode) {}

You can also specify these methods as attributes of both regular elements and components:

    (div(oncreate=function() trace('oncreate')))
    (MyComponent(oncreate=function() trace('oncreate')))

State

Mithril manages component state by cloning a component's fields post-constructor and storing them in vnode.state. Because component instances can be cached and reused by Mithril, accessing state must be thru vnode.state unless the initial state is being set.

class StatefulComponent extends Component {
    var someState = "my state"; // set initial state value here or in constructor
    var someMoreState:String;
    
    override public function new(vnode:Vnode) {
        someMoreState = "other state"; // can also set initial component state here
    }
    
    override public function view(vnode:Vnode) @m[
        (div > vnode.state.someState) // access it via vnode.state
            [vnode.state.someMoreState]
    ]
}

Rendering

Components can be rendered by passing a Component class to Mithril:

M.mount(js.Browser.document.body, MyComponent);

Or may be rendered on the server as html (string):

HTMLRenderer.render(@m[ (div > 'view') ]).then(function(html) Sys.print(html))

Mithril routing is also supported:

M.route(js.Browser.document.body, "/", routes);

Usage

Any of your class methods can use ithril syntax if you either implement ithril.IthrilView or extend ithril.Component.

import ithril.*;

class Web extends Component {
	public function layout() @m[
		(!doctype)
		(meta[charset="utf-8"])
		(link[href="layout.css"][rel="stylesheet"])
		(body)
			[view()]
		(script[src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.0/mithril.min.js"])
		(script[src="main.js"])
	];

	override public function view(vnode) @m[
		(div.intro)
			(h1 > 'Ithril example')
			(p > 'Hello world')
	];

	public static function main() {
		// On the server
		#if !js
		Sys.print(HTMLRenderer.render(new Web({ }).layout()));
		#else
		// On the client
		M.mount(js.Browser.document.body, new Web({ }));
		#end
	}
}

Output

@m[ (div(attrs)) ] is transpiled to Mithril hyperscript m('div', attrs). On the browser end, it's passed directly to Mithril. In server instances ithril.HTMLRenderer can be is used to render HTML.

Sample Website

An example website can be found at examples/website. You will need node, npm, sass, and either closure or uglifyjs installed in order to build and run it.

Initial build: (this will run npm install)

cd examples/website
haxe build.hxml

Start webserver: (listens on localhost:4200, and restarts when webserver.js changes)

npm run start

Auto-build: (rebuilds on file changes)

npm run autobuild

ithril's People

Contributors

benmerckx avatar dfadev avatar

Watchers

 avatar  avatar

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.