├── .travis.yml
├── examples
├── server.js
└── composition.js
├── .gitignore
├── package.json
├── LICENSE
├── index.js
├── test.js
└── README.md
/.travis.yml:
--------------------------------------------------------------------------------
1 | node_js:
2 | - "1"
3 | - "2"
4 | sudo: false
5 | language: node_js
6 | script: "npm run test-cov"
7 | after_script: "npm i -g codecov.io && cat ./coverage/lcov.info | codecov"
8 |
--------------------------------------------------------------------------------
/examples/server.js:
--------------------------------------------------------------------------------
1 | const vel = require('vel')
2 |
3 | const el = vel((h, state) => {
4 | return h.html(`
5 |
Hello my name is ${state.name}
6 | `)
7 | })
8 |
9 | el.toString({ name: 'Happy Hank' })
10 | // => Hello my name is Happy Hank
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # tmp files
2 | lib-cov
3 | *.seed
4 | *.log
5 | *.csv
6 | *.dat
7 | *.out
8 | *.pid
9 | *.gz
10 |
11 | # tmp folders
12 | pids/
13 | logs/
14 | results/
15 | coverage/
16 |
17 | # node.js
18 | node_modules/
19 | npm-debug.log
20 |
21 | # osx
22 | .DS_Store
23 |
--------------------------------------------------------------------------------
/examples/composition.js:
--------------------------------------------------------------------------------
1 | const vel = require('vel')
2 |
3 | const header = vel((h, state) => {
4 | return h('h1', state.header)
5 | })
6 |
7 | const body = vel((h, state) => {
8 | return h('p', state.body)
9 | })
10 |
11 | const wrap = vel((h, state) => {
12 | return h('section', [
13 | header.vtree(state),
14 | body.vtree(state)
15 | ])
16 | })
17 |
18 | const state = {
19 | header: 'my header',
20 | body: 'lorem ipsum'
21 | }
22 |
23 | document.body.appendChild(wrap.render(state))
24 | // =>
25 | // => my header
26 | // => lorem ipsum
27 | // =>
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vel",
3 | "version": "1.2.0",
4 | "description": "Create and render virtual-dom elements with ease",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "standard && NODE_ENV=test node test",
8 | "test-cov": "standard && NODE_ENV=test istanbul cover test.js",
9 | "watch": "watch 'npm t'"
10 | },
11 | "repository": "yoshuawuyts/vel",
12 | "keywords": [
13 | "helper",
14 | "main-loop",
15 | "render",
16 | "vdom",
17 | "virtual-dom",
18 | "vtree"
19 | ],
20 | "license": "MIT",
21 | "dependencies": {
22 | "dom-delegator": "^13.1.0",
23 | "main-loop": "^3.1.0",
24 | "vdom-to-html": "^2.1.1",
25 | "virtual-dom": "~2.0.1",
26 | "virtual-html": "^2.0.0",
27 | "virtual-hyperscript-svg": "^2.0.0"
28 | },
29 | "devDependencies": {
30 | "istanbul": "^0.3.17",
31 | "jsdom": "^5.6.1",
32 | "noop2": "^2.0.0",
33 | "raf": "^3.1.0",
34 | "standard": "^4.5.4",
35 | "tape": "^4.0.1",
36 | "watch": "^0.16.0"
37 | },
38 | "files": [
39 | "LICENSE",
40 | "README.md",
41 | "index.js"
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const toHtml = require('vdom-to-html')
2 | const mainLoop = require('main-loop')
3 | const vdom = require('virtual-dom')
4 | const h = require('virtual-dom/h')
5 | const assert = require('assert')
6 |
7 | h.svg = require('virtual-hyperscript-svg')
8 | h.html = require('virtual-html')
9 |
10 | // required for event delegation
11 | // to be handled correctly
12 | require('dom-delegator')()
13 |
14 | module.exports = vel
15 |
16 | // initialize a new virtual element
17 | // fn -> null
18 | function vel (rend) {
19 | assert.equal(typeof rend, 'function')
20 |
21 | var update = null
22 | render.toString = toString
23 | render.render = render
24 | render.vtree = vtree
25 | return render
26 |
27 | // render the element's vdom tree to DOM nodes
28 | // which can be mounted on the DOM
29 | // any? -> DOMNode
30 | function render (state) {
31 | if (update) return update(state)
32 | const loop = mainLoop(state, renderFn(rend), vdom)
33 | update = loop.update
34 | return loop.target
35 | }
36 |
37 | // render the element's vdom tree to a string
38 | // any? -> str
39 | function toString (state) {
40 | return toHtml(renderFn(rend)(state))
41 | }
42 |
43 | // Get the element's vdom tree.
44 | // any? -> obj
45 | function vtree (state) {
46 | return rend(h, state)
47 | }
48 | }
49 |
50 | // render function
51 | // (fn, fn) -> fn(any?) -> obj
52 | function renderFn (rend) {
53 | return function (state) {
54 | return rend(h, state)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | const noop = require('noop2')
2 | const test = require('tape')
3 | const raf = require('raf')
4 | const vel = require('./')
5 |
6 | test('el = vel() should assert input types', function (t) {
7 | t.plan(1)
8 | t.throws(vel, /function/)
9 | })
10 |
11 | test('el = vel() should be a function', function (t) {
12 | t.plan(1)
13 | const el = vel(noop)
14 | t.equal(typeof el, 'function')
15 | })
16 |
17 | test('el() should render an element', function (t) {
18 | t.plan(5)
19 |
20 | const el = vel(function (h, state) {
21 | t.equal(typeof state, 'object')
22 | t.equal(typeof h, 'function')
23 | t.equal(state.foo, 'bar')
24 | return h('div')
25 | })
26 | const node = el({ foo: 'bar' })
27 |
28 | t.equal(typeof node, 'object')
29 | t.equal(node.nodeType, 1, 'is dom')
30 | })
31 |
32 | test('el() can parse string templates', function (t) {
33 | t.plan(2)
34 |
35 | const el = vel(function (h, state) {
36 | return h.html('hello silly world
')
37 | })
38 | const node = el({ foo: 'bar' })
39 |
40 | t.equal(typeof node, 'object')
41 | t.equal(node.nodeType, 1, 'is dom')
42 | })
43 |
44 | test('el can create svg elements', function (t) {
45 | t.plan(2)
46 |
47 | const el = vel(function (h, state) {
48 | return h.svg('svg', { width: 400, height: 300 })
49 | })
50 | const node = el()
51 |
52 | t.equal(typeof node, 'object')
53 | t.equal(node.tagName, 'svg')
54 | })
55 |
56 | test('calling el() twice should update an element', function (t) {
57 | t.plan(8)
58 |
59 | const el = vel(function (h, state) {
60 | t.equal(typeof state, 'object')
61 | t.equal(typeof h, 'function')
62 | return h('div', state.foo)
63 | })
64 |
65 | const node = el({ foo: 'bar' })
66 |
67 | t.equal(typeof node, 'object')
68 | t.equal(typeof node.childNodes[0], 'object')
69 | t.equal(node.childNodes[0].data, 'bar')
70 |
71 | el({ foo: 'baz' })
72 | raf(function () {
73 | t.equal(node.childNodes[0].data, 'baz')
74 | })
75 | })
76 |
77 | test('el() and el.render() are aliases', function (t) {
78 | t.plan(1)
79 | const el = vel(noop)
80 | t.equal(el, el.render)
81 | })
82 |
83 | test('calling el.toString() renders to string', function (t) {
84 | t.plan(1)
85 | const el = vel(function (h, state) {
86 | return h('div', 'hello ' + state + ' world')
87 | })
88 | const str = el.toString('cruel')
89 | t.equal(str, 'hello cruel world
')
90 | })
91 |
92 | test('el.vtree() returns the vdom tree', function (t) {
93 | t.plan(2)
94 | const el = vel(function (h, state) {
95 | return h('div', 'hello ' + state + ' world')
96 | })
97 | const vtree = el.vtree('cruel')
98 | t.equal(typeof vtree, 'object')
99 | t.equal(vtree.tagName, 'DIV')
100 | })
101 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vel
2 | [![NPM version][npm-image]][npm-url]
3 | [![build status][travis-image]][travis-url]
4 | [![Test coverage][codecov-image]][codecov-url]
5 | [![Downloads][downloads-image]][downloads-url]
6 | [![js-standard-style][standard-image]][standard-url]
7 |
8 | Efficiently create and render
9 | [virtual-dom](https://github.com/Matt-Esch/virtual-dom) elements.
10 |
11 | ## Installation
12 | ```bash
13 | $ npm install vel
14 | ```
15 |
16 | ## Usage
17 | ```js
18 | const vel = require('vel')
19 |
20 | const el = vel((h, state) => h.html(`hello ${state.type} world
`))
21 | const node = el({ type: 'cruel' })
22 |
23 | document.body.appendChild(node)
24 | // hello cruel world
25 | ```
26 |
27 | ## API
28 | ### el = vel(cb(h, state))
29 | Initialize a new virtual element. Listen to the `render` event. Expects a
30 | `vdom` tree to be returned. `h` accepts [`virtual-dom` elements](https://github.com/Matt-Esch/virtual-dom),
31 | `h.html` accepts
32 | [HTML strings](https://github.com/azer/virtual-html) and `h.svg`
33 | accepts
34 | [`virtual-dom` SVG elements](https://github.com/substack/virtual-hyperscript-svg).
35 |
36 | ### el([state])
37 | Render the element's vdom tree to DOM nodes which can be mounted on the DOM.
38 | Uses [main-loop](https://github.com/Raynos/main-loop) under the hood. Calling
39 | the method again will re-render the DOM nodes with the new state. Alias:
40 | `el.render([state])`.
41 |
42 | ### el.toString([state])
43 | Render the element's vdom tree to a string. For example useful to pre-render
44 | HTML on the server, or save to a static file.
45 |
46 | ### vtree = el.vtree([data])
47 | Get the element's vdom tree. Useful for element composition.
48 |
49 | ## FAQ
50 | ### why did you write this?
51 | Using `virtual-dom` requires quite some boilerplate. `vel` removes the need for
52 | that boilerplate without adding extra features, making it easier to write
53 | `virtual-dom` systems.
54 |
55 | ### why is there no state transport mechanism included?
56 | `vel` does one thing, and only one thing. Instead of including a state transport
57 | mechanism I felt it made more sense to let users decide for themselves how they
58 | want their state to flow between components.
59 |
60 | ### what's the difference between virtual-dom and react?
61 | `react` is an opinionated framework that uses non-standard syntax to create
62 | systems. It forces users to write JS in OO style and is hard to switch from
63 | once you buy into it. `virtual-dom` does away with those opinions, giving users
64 | a blazingly fast rendering engine without the overhead of a framework.
65 |
66 | ### this module sound lot like base-element!
67 | Yeah, definitely! I'm actually a huge fan of
68 | [`base-element`](https://www.npmjs.com/package/base-element). However I wanted
69 | something a little more barebone favoring composition over inheritance. If
70 | inheritance is your thing, definitely check out
71 | [`base-element`](https://www.npmjs.com/package/base-element) (and say hi to
72 | [@shama](https://github.com/shama) for me :grin:).
73 |
74 | ## See Also
75 | - [virtual-dom](https://github.com/Matt-Esch/virtual-dom)
76 | - [virtual-hyperscript-svg](https://github.com/substack/virtual-hyperscript-svg)
77 | - [main-loop](https://github.com/Raynos/main-loop)
78 | - [virtual-html](https://github.com/azer/virtual-html)
79 | - [vdom-to-html](https://github.com/nthtran/vdom-to-html/)
80 |
81 | ## License
82 | [MIT](https://tldrlegal.com/license/mit-license)
83 |
84 | [npm-image]: https://img.shields.io/npm/v/vel.svg?style=flat-square
85 | [npm-url]: https://npmjs.org/package/vel
86 | [travis-image]: https://img.shields.io/travis/yoshuawuyts/vel/master.svg?style=flat-square
87 | [travis-url]: https://travis-ci.org/yoshuawuyts/vel
88 | [codecov-image]: https://img.shields.io/codecov/c/github/yoshuawuyts/vel/master.svg?style=flat-square
89 | [codecov-url]: https://codecov.io/github/yoshuawuyts/vel
90 | [downloads-image]: http://img.shields.io/npm/dm/vel.svg?style=flat-square
91 | [downloads-url]: https://npmjs.org/package/vel
92 | [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
93 | [standard-url]: https://github.com/feross/standard
94 |
--------------------------------------------------------------------------------