DIO.js

Dio is a blazing fast, lightweight (~9kb) feature rich Virtual DOM framework.
- ~9kb minified+gzipped
- ~24kb minified

Browser Support
- Edge
- IE 8+
- Chrome
- Firefox
- Safari
Installation
direct download
<script src=dio.min.js></script>
CDN
<script src=https://cdnjs.cloudflare.com/ajax/libs/dio/2.0.0/dio.min.js></script>
<script src=https://cdn.jsdelivr.net/dio/2.0.0/dio.min.js></script>
<script src=https://unpkg.com/dio.js@2.0.0/dio.min.js></script>
bower
bower install dio.js
npm
npm install dio.js --save
You can also play with Dio on this jsbin
Getting Started
Dio is a blazing fast, lightweight (~9kb) feature rich Virtual DOM framework
built around the concept that any function/object can become a component.
Components in Dio share the same api's as react with a few additions,
this means that you can easily port both ways between Dio and React as and when needed
without any significant changes to the code base,
the minimal change in most cases being a simple React, ReactDOM = dio
.
Having said that Dio can be used as just a "view" library but it does come
self containeed with everything you would need to build an application,
from routing, http requests, server-side rendering to testing, state stores, animations and more.
In that respect this getting started guide aims to show you how to go from zero to hello world in Dio.
Hello world
function HelloWorld () {
return {
render: function (props) {
return h('h1', props.text);
}
}
}
dio.render(HelloWorld)({text: 'Hello World'});
Will mount a h1 element onto the page the contents of which will be 'Hello World'.
Performance
API Reference
components schema
{
shouldComponentUpdate: (newProps, newState) => {}
componentWillReceiveProps: (newProps) => {}
componentWillUpdate: (newProps, newState) => {}
componentDidUpdate: (oldProps, oldState) => {}
componentWillMount: () => {}
componentDidMount: () => {}
componentWillUnmount: () => {}
this.withAttr ({string|string[]}, {function|function[]})
this.forceUpdate: ()
this.setState: ({Object}, callback: {function=})
this.setProps: ({Object})
displayName: {string}
propTypes: {Object}
statics: {Object}
render: (props, state, this) => {}
}
creating hyperscript objects
h(
tag: {String},
props?|children?: {Object} | {Array|Object}...,
children?: {Array|Object}...
)
h('.wrap')
h('input[type=checkbox]')
h('input', {value: 'text', onInput: ()=>{}})
h('div', 'Text')
h('div', h('span', 'Text'))
h('div', [h('h1', '1st'), h('h1', '2nd'), ...])
h('div', {innerHTML: "<script>alert('hello')</script>"});
h(Component, {who: 'World'}, 1, 2, 3, 4)
h('div', ComponentFunction)
h('div', Component)
h('@fragment', 'Hello', 'World')
h('@foo', 'Hello', 'World')
{
nodeType: 1,
type: 'div',
props: {},
children: [
{
nodeType: 3,
type: 'text',
props: {},
children: ['Hello World']
}
]
}
h('div', 'Hello World');
dio.createClass
dio.createClass({Function|Object})
class Component extends dio.Component {
render() {
}
}
var myComponent = dio.createClass({
render: () => { return h('div') }
});
var myComponent = dio.createClass(function () {
return {
render: () => { return h('div') }
};
});
class myComponent extends dio.Component {
render() {
return h('div')
}
}
dio.render
dio.render(component: {function|Object},mount?: {string|Element})
var instance = dio.render(Component);
instance(props: {Object});
dio.render(h(Component, {...props}, ...children));
component examples.
function () {
return h('div', 'Hello World')
}
function () {
return {
render: function () {
return h('div', 'Hello World')
}
}
}
h('div', 'Hello World');
{
render: function () {
return h('div', 'Hello World')
}
}
dio.createClass({
render: function () {
return h('div', 'Hello World')
}
})
dio.createClass(function () {
return {
render: function () {
return h('div', 'Hello World')
}
}
})
class Component extends dio.Component {
constructor(props) {
super(props)
}
render() {
return h('div', 'Hello World')
}
}
Components created with .createClass/extends dio.Component
are
statefull by default. There are also other scenarios that pure functions
may become statefull, below are some examples.
function Pure () {
return {
render: function () {
return h('h1');
}
}
}
function Parent () {
return {
render: function () {
return h('div', Pure);
}
}
}
var render = dio.render(Pure);
var render = dio.render(Parent);
Note that in the getting started section 'Hello World'
we did not create a component with dio.createClass()
but rather just used a pure function that we passed
to dio.render(here)
this is because
.render
will create a component if
what is passed to it is not already a component as detailed above.
mount examples.
document
document.body
document.querySelector('.myapp')
'.myapp'
document.createElement('div')
document.createDocumentFragment();
function el () {
return document.body;
}
dio.render(__, mount);
How do i render one component within another?
Components are for the most part functions(statefull/stateless),
to render place them h('div', A)
or h('div', h(A, {}, []))
.
note: render instances(created with .render) are not components
function () {
var elementHolder = dio.stream();
return {
render: function () {
return h('div', {ref: elementHolder},
Foo({text: 'Hello'}),
Bar({text: 'World'})
)
}
}
}
dio.router
dio.router(
routes: {(function|Object)},
rootAddress: {string=},
onInit: {(string|function)=},
mount: {(string|Node)=}
middleware: {function}
)
dio.router({(function|Object)}, {
root: {string=},
init: {(string|function)=},
mount: {(string|Node)=}
middleware: {function}
})
example router
dio.router({
'/': function (data) {
dio.render(h(home, data))
},
'/user/:id': function (data) {
dio.render(H(user, data));
}
}, '/backend', '/user/sultan')
dio.router({
'/': ComponentA,
'/user/:id': ComponentA
}, {
mount: document.body
});
You can then assign this route to a variable and use it to navigate across views
var myrouter = ...
myrouter.nav('/user/sultan')
myrouter.go(-2)
myrouter.back()
myrouter.forward()
dio.createStore
dio.createStore(
reducer: {(function|Object)},
initalState: {Any}
enhancer: {Function}
)
Rather exactly like redux createStore
with the different of .connect
that accepts a component & mount/callback
with which to update everytime the store is updated.
Which is mostly a short hand for creating a listerner with .subscribe
that updates your component on state changes.
var store = dio.createStore(reducer: {Function})
var store = dio.createStore(object of reducers: {Object})
store.dispatch({type: '' ...})
store.getState()
store.subscribe(listener: {Function})
store.connect(callback: {function})
store.connect(callback: {(function|Object)}, element: {(string|Node)})
dio.renderToString
Like the name suggests this methods outputs the html
of a specific component with the props passed
to it, this is normally used within the context of server-side rendering.
When used as a server-side tool add the attribute data-hydrate
to the container you wish to ouput the html, this will allow DIO to
hydrate the current dom on initial mount.
dio.renderToString(h('div', 'Text'));
dio.stream
dio.stream(store: {Any|Function}, mapper);
var alwaysString = dio.stream(100, String);
alwaysString()
var foo = dio.stream('initial value')
foo('changed value')
foo('changed')('again')
foo()
var bar = foo.map(function(foo){
return foo + ' and bar';
});
bar()
foo('hello world')
bar()
var faz = dio.stream.combine(function(foo, bar, prevValueOfFaz){
return foo() + bar();
}, foo, bar);
foo(1)
bar(2)
faz()
faz.then(function(faz){
console.log(faz);
});
faz('changed')
faz.then(fn).then(fn)....
dio.stream.all([dep1, dep2]).then(fn);
var async = dio.stream(function (resolve, reject) {
setTimeout(resolve, 500, 'value');
});
var async = dio.stream(function () {
setTimeout(reject, 500, 'just because');
}).then(function (value) {
console.log(value + 'resolved')
}).catch(function (reason) {
console.log('why:' + reason)
});
var foo = dio.stream(function (resolve, reject) {
xhr.onload = resolve;
xhr.onerror = reject;
xhr.send();
});
foo.then(function (value) { return 100 })
.then(function (value) { console.log(value+20) })
.catch(function (value) { return 100 })
.catch(function (value) { console.log(value+200) })
var numbers = stream();
var sum = stream.scan(function(sum, numbers) {
return sum + numbers();
}, 0, numbers);
numbers(2)(3)(5);
sum();
dio.curry
var foo = dio.curry(
fn: {function},
args...: {any[]},
preventDefault: {boolean},
)
onClick: dio.curry(
(a) => {'look no e.preventDefault()'},
['a'],
true
)
function DoesOneThing (component, arg1, arg2) {
component.setState({...});
}
h('input', {
onInput: dio.curry(DoesOneThing, [this, 1, 2], true)
})
dio.createFactory
dio.createFactory(element);
Like it would work in react createFactory returns a function that
produces a hyperscript element of a single given type.
var div = dio.createFactory('div');
h('div', 'Hello World');
div('Hello World');
dio.request
a http helper that makes ajax requests.
dio.request(
url: {String},
payload?: {Object},
enctype?: {String},
withCredentials?: {Boolean}
)
dio.request.post('/url', {id: 1234}, 'json')
.then((res)=>{return res})
.then((res)=>{'do something'})
.catch((err)=>{throw err});
dio.request({
method: 'GET',
url: '/url',
payload: {id: 1234},
enctype: 'json',
withCredentials: false
}).then((res)=>{return res}).catch((err)=>{throw err});
dio.animateWith
dio.animateWith.flip(
className: {string},
duration: {number},
transform: {string},
transformOrigin: {string},
easing: {string}
)(
element: {(Node|string)}
)
dio.animateWith.transitions(
className: {string},
type?: {(string|number|boolean)}
)(
element: {Node},
callback: {function} => (element: {Node}, transitions: {function})
)
dio.animateWith.animations(...)
for example dio.animateWith.flip
can be used within a render as follows
render: function () {
return h('.card',
{
onclick: dio.animateWith.flip('active-state', 200)
},
''
)
}
since dio.animateWith.flip(...)
returns a function this is the same as
dio.animateWith.flip('active-state', 200)(elementNode)
another animation helper is animateWith.transitions
and animateWith.animations
the callback function
supplied after the element will execute after the
resulting animation/transition from adding/removing the class completes.
handleDelete: function (e) {
var element = e.currentTarget,
self = this
dio.animateWith.transitions('slideUp')(element, function(next, el) {
store.dispatch({type: 'DELETE', id: 1234});
next('slideLeft')(el, function (el, next) {
next('slideLeft', -1)(el);
});
})
}
dio.PropTypes
validates props passed to components insuring they are
of the the specificied type. The built in validtors work
exactly as they do in react land namely.
[
number, string, bool, array, object, func, element, node
any, shape, instanceOf, oneOf, oneOfType, arrayOf, objectOf
]
and you can also create your own validators though
it should be noted that propTypes/validations are only evaluated
when NODE_ENV
or process.env.NODE_ENV
are defined and set to 'development'
.
dio.createClass({
propTypes: {
id: dio.PropTypes.string.isRequired,
name: dio.PropTypes.string,
custom: function (
props,
propName,
displayName,
createInvalidPropTypeError,
createRequiredPropTypeError
) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + displayName + '`. Validation failed.'
);
}
}
}
render: function () {
}
})
createInvalidPropTypeError(
propName: {String},
propValue: {Any},
displayName: {String},
expectedType: {String}
)
createRequiredPropTypeError(
propName: {String},
displayName: {String}
)
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
return createInvalidPropTypeError(
propName, props[propName], displayName, 'expected type'
)
dio.injectWindowDependency
injects a mock window object to be used for writting tests for
features that do not exist outside of the browser enviroment,
like XMLHttpRequest
and other #document
operations.
dio.injectWindowDependency({Object})
Utilities
addEventListener:
bind,
assign,
keys,
assign,
keys,
reduce,
reduceRight,
filter
map,
forEach,
slice,
splice
flatten
isObject,
isFunction,
isString,
isArray,
isDefined