Skip to content

Commit e21d91a

Browse files
authored
Merge pull request #20 from wavesoft/devel/0.2.2
v0.2.2 Release
2 parents 5e2376b + 962e78e commit e21d91a

File tree

6 files changed

+175
-76
lines changed

6 files changed

+175
-76
lines changed

README.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# .dom [![Build Status](https://travis-ci.org/wavesoft/dot-dom.svg?branch=master)](https://travis-ci.org/wavesoft/dot-dom) [![Try it in codepen.io](https://img.shields.io/badge/Try%20it-codepen.io-blue.svg)](https://codepen.io/anon/pen/YNdNwv?editors=0010)
22

3-
> A tiny (510 byte) virtual DOM template engine for embedded projects
3+
> A tiny (511 byte) virtual DOM template engine for embedded projects
44
55
| <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/edge.png" alt="IE / Edge" width="16px" height="16px" /> IE / Edge | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/firefox.png" alt="Firefox" width="16px" height="16px" /> Firefox | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome.png" alt="Chrome" width="16px" height="16px" /> Chrome | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari.png" alt="Safari" width="16px" height="16px" /> Safari | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/opera.png" alt="Opera" width="16px" height="16px" /> Opera | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari-ios.png" alt="iOS Safari" width="16px" height="16px" /> iOS Safari | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome-android.png" alt="Chrome for Android" width="16px" height="16px" /> Chrome for Android |
66
| --------- | --------- | --------- | --------- | --------- | --------- | --------- |
@@ -12,7 +12,7 @@ Why? Because with such library you can create powerful GUIs in tight space envir
1212

1313
### Features
1414

15-
* _Tiny by design_ : The library should never exceed the 512 bytes in size. The goal is not to have yet another template engine, but to have as many features as possible in 512 bytes. If a new feature is needed, an other must be sacraficed or the scope must be reduced.
15+
* _Tiny by design_ : The library should never exceed the 512 bytes in size. The goal is not to have yet another template engine, but to have as many features as possible in 512 bytes. If a new feature is needed, an other must be sacraficed or the scope must be reduced.
1616

1717
* _Built for the future_ : The library is heavily exploiting the ES6 specifications, meaning that it's **not** supported by older borwsers. Currently it's supported by the 70% of the browsers in the market, but expect this to be 90% within the next year.
1818

@@ -25,16 +25,16 @@ Why? Because with such library you can create powerful GUIs in tight space envir
2525

2626
## Installation
2727

28-
For minimum footprint, include `dotdom.min.js.gz` (510b) to your project.
28+
For minimum footprint, include `dotdom.min.js.gz` (511b) to your project.
2929

3030
```html
3131
<script src="dotdom.min.js.gz" />
3232
```
3333
34-
Alternatively you can just include the minified version of the library directly before your script. Just copy-paste the following (755b):
34+
Alternatively you can just include the minified version of the library directly before your script. Just copy-paste the following (779b):
3535
3636
```js
37-
((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]&&k.unshift(j)&&{C:k}||(j.C=k)&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v,w,x,y=n.P[v])=>'style'==v?c.assign(u[v],y):'C'!=v&&(u[v]=y))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>h(f.bind(a,j))})})(window,document,Object,Symbol(),{});
37+
((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]?{C:[].concat(j,...k)}:(j.C=[].concat(...k))&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v)=>'style'==v?c.assign(u[v],n.P[v]):u[v]!==n.P[v]&&(u[v]=n.P[v]))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>i[j]||h(f.bind(a,j))})})(window,document,Object,Symbol(),{});
3838
```
3939
4040
## Examples
@@ -210,6 +210,29 @@ component.
210210
211211
Properties and children are optional and they can be omitted.
212212
213+
#### Functional Components
214+
215+
Instead of a tag name you can provide a function that returns a Virtual DOM
216+
according to some higher-level logic. Such function have the following signature:
217+
218+
```js
219+
const Component = (props, state, setState) {
220+
221+
// Return your Virtual DOM
222+
return div( ... )
223+
}
224+
```
225+
226+
The `props` property contains the properties object as given when the component
227+
was created.
228+
229+
The `state` is initialized to an empty object `{}` and it's updated by calling
230+
the `setState({ newState })` method. The latter will also trigger an update to
231+
the component and it's children.
232+
233+
You can also assign properties to the `state` object directly if you don't want
234+
to cause an update.
235+
213236
### Tag Shorthand `tag( [properties], [children ...] )`
214237
215238
```js
@@ -289,8 +312,8 @@ Are you interested in contributing to **.dom**? You are more than welcome! Just
289312
global.R = render = (
290313
vnodes, // Flat-code comments start on column 70 and
291314
dom, // wrap after column 120.
292-
315+
293316
/* Logical separations can be commented like this */
294-
317+
295318
...
296319
```

dotdom.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dotdom.min.js.gz

1 Byte
Binary file not shown.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"name": "dot-dom",
3-
"version": "0.2.1",
3+
"version": "0.2.2",
44
"description": "A tiny (less than 512 byte) template engine that uses virtual DOM and some of react principles",
5-
"main": "dotdom.min.js",
5+
"main": "src/dotdom.js",
66
"scripts": {
77
"test": "./node_modules/.bin/jest",
8-
"build": "./node_modules/.bin/babili src/dotdom.js | tee dotdom.min.js | gzip -9 > dotdom.min.js.gz"
8+
"build": "cat src/dotdom.js | perl -0pe 's/BEGIN NPM-GLUE.*END NPM-GLUE//s' | ./node_modules/.bin/babili | tee dotdom.min.js | gzip -9 > dotdom.min.js.gz"
99
},
1010
"repository": {
1111
"type": "git",

src/__tests__/dotdom-test.js

Lines changed: 119 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,141 @@
1-
require('../dotdom');
2-
const dd = window;
1+
const dd = require('../dotdom');
32

43
describe('.dom', function () {
54

65
describe('#H', function () {
7-
it('should create vnode without arguments', function () {
8-
const vdom = dd.H('div');
96

10-
expect(vdom.E).toEqual('div');
11-
expect(vdom.P).toEqual({C: []});
12-
});
7+
describe('Factory', function () {
138

14-
it('should create vnode with props', function () {
15-
const vdom = dd.H('div', {foo: 'bar'});
9+
it('should create vnode without arguments', function () {
10+
const vdom = dd.H('div');
1611

17-
expect(vdom.E).toEqual('div');
18-
expect(vdom.P).toEqual({foo: 'bar', C: []});
19-
});
12+
expect(vdom.E).toEqual('div');
13+
expect(vdom.P).toEqual({C: []});
14+
});
2015

21-
it('should create vnode with props and children', function () {
22-
const cdom = dd.H('div');
23-
const vdom = dd.H('div', {foo: 'bar'}, cdom);
16+
it('should create vnode with props', function () {
17+
const vdom = dd.H('div', {foo: 'bar'});
2418

25-
expect(vdom.E).toEqual('div');
26-
expect(vdom.P).toEqual({
27-
foo: 'bar',
28-
C: [ cdom ]
19+
expect(vdom.E).toEqual('div');
20+
expect(vdom.P).toEqual({foo: 'bar', C: []});
2921
});
30-
});
3122

32-
it('should create vnode with props and mixed children', function () {
33-
const cdom = dd.H('div');
34-
const vdom = dd.H('div', {foo: 'bar'}, 'foo', cdom);
23+
it('should create vnode with props and children', function () {
24+
const cdom = dd.H('div');
25+
const vdom = dd.H('div', {foo: 'bar'}, cdom);
3526

36-
expect(vdom.E).toEqual('div');
37-
expect(vdom.P).toEqual({
38-
foo: 'bar',
39-
C: [ 'foo', cdom ]
27+
expect(vdom.E).toEqual('div');
28+
expect(vdom.P).toEqual({
29+
foo: 'bar',
30+
C: [ cdom ]
31+
});
32+
});
33+
34+
it('should create vnode with props and children as array', function () {
35+
const cdom1 = dd.H('div');
36+
const cdom2 = dd.H('div');
37+
const cdom3 = dd.H('div');
38+
const vdom = dd.H('div', {foo: 'bar'}, cdom1, [cdom2, cdom3]);
39+
40+
expect(vdom.E).toEqual('div');
41+
expect(vdom.P).toEqual({
42+
foo: 'bar',
43+
C: [ cdom1, cdom2, cdom3 ]
44+
});
4045
});
41-
});
4246

43-
it('should create vnode with props and string children', function () {
44-
const vdom = dd.H('div', {foo: 'bar'}, 'foo');
47+
it('should create vnode with props and mixed children', function () {
48+
const cdom = dd.H('div');
49+
const vdom = dd.H('div', {foo: 'bar'}, 'foo', cdom);
4550

46-
expect(vdom.E).toEqual('div');
47-
expect(vdom.P).toEqual({
48-
foo: 'bar',
49-
C: [ 'foo' ]
51+
expect(vdom.E).toEqual('div');
52+
expect(vdom.P).toEqual({
53+
foo: 'bar',
54+
C: [ 'foo', cdom ]
55+
});
5056
});
51-
});
5257

53-
it('should create vnode with only child', function () {
54-
const vdom = dd.H('div', 'foo');
58+
it('should create vnode with props and string children', function () {
59+
const vdom = dd.H('div', {foo: 'bar'}, 'foo');
5560

56-
expect(vdom.E).toEqual('div');
57-
expect(vdom.P).toEqual({
58-
C: [ 'foo' ]
61+
expect(vdom.E).toEqual('div');
62+
expect(vdom.P).toEqual({
63+
foo: 'bar',
64+
C: [ 'foo' ]
65+
});
5966
});
67+
68+
it('should create vnode with only child', function () {
69+
const vdom = dd.H('div', 'foo');
70+
71+
expect(vdom.E).toEqual('div');
72+
expect(vdom.P).toEqual({
73+
C: [ 'foo' ]
74+
});
75+
});
76+
77+
it('should create vnode with children', function () {
78+
const vdom = dd.H('div', 'foo', 'bar', 'baz');
79+
80+
expect(vdom.E).toEqual('div');
81+
expect(vdom.P).toEqual({
82+
C: [ 'foo', 'bar', 'baz' ]
83+
});
84+
});
85+
86+
it('should create vnode with children in arrays', function () {
87+
const vdom = dd.H('div', 'foo', ['bar', 'baz']);
88+
89+
expect(vdom.E).toEqual('div');
90+
expect(vdom.P).toEqual({
91+
C: [ 'foo', 'bar', 'baz' ]
92+
});
93+
});
94+
95+
it('should create vnode with only mixed children', function () {
96+
const cdom = dd.H('div');
97+
const vdom = dd.H('div', cdom, 'foo');
98+
99+
expect(vdom.E).toEqual('div');
100+
expect(vdom.P).toEqual({
101+
C: [ cdom, 'foo' ]
102+
});
103+
});
104+
60105
});
61106

62-
it('should create vnode with only mixed children', function () {
63-
const cdom = dd.H('div');
64-
const vdom = dd.H('div', cdom, 'foo');
107+
describe('Proxy', function () {
108+
109+
it('H.apply should be proxied', function () {
110+
const cdom = dd.H('div');
111+
const vdom = dd.H.apply({}, ['div', cdom, 'foo']);
112+
113+
expect(vdom.E).toEqual('div');
114+
expect(vdom.P).toEqual({
115+
C: [ cdom, 'foo' ]
116+
});
117+
});
118+
119+
it('H.call should be proxied', function () {
120+
const cdom = dd.H('div');
121+
const vdom = dd.H.call({}, 'div', cdom, 'foo');
122+
123+
expect(vdom.E).toEqual('div');
124+
expect(vdom.P).toEqual({
125+
C: [ cdom, 'foo' ]
126+
});
127+
});
65128

66-
expect(vdom.E).toEqual('div');
67-
expect(vdom.P).toEqual({
68-
C: [ cdom, 'foo' ]
129+
it('H.tag should be a shorthand', function () {
130+
const cdom = dd.H('div');
131+
const vdom = dd.H.div(cdom, 'foo');
132+
133+
expect(vdom.E).toEqual('div');
134+
expect(vdom.P).toEqual({
135+
C: [ cdom, 'foo' ]
136+
});
69137
});
138+
70139
});
71140

72141
});
@@ -292,8 +361,8 @@ describe('.dom', function () {
292361
}
293362
const HostComponent = function() {
294363
return dd.H('div',
295-
H(Component),
296-
H(Component)
364+
dd.H(Component),
365+
dd.H(Component)
297366
)
298367
}
299368
const vdom = dd.H(HostComponent);
@@ -379,8 +448,8 @@ describe('.dom', function () {
379448
}, `${clicks} clicks`)
380449
}
381450
const vdom = dd.H('div',
382-
H(Component),
383-
H(Component)
451+
dd.H(Component),
452+
dd.H(Component)
384453
);
385454

386455
dd.R(vdom, dom)

src/dotdom.js

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@
1515
* See the License for the specific language governing permissions and
1616
* limitations under the License.
1717
*/
18+
19+
/* BEGIN NPM-GLUE */
20+
21+
// This code block will be striped when building the stand-alone version.
22+
// When using `npm` this exports the correct functions in order to be easily
23+
// imported in the correct scope, without leaking to the global scope.
24+
25+
const window = {};
26+
module.exports = window;
27+
28+
/* END NPM-GLUE */
29+
1830
((global, document, Object, vnodeFlag, globalState, createElement, render, wrapClassProxy) => {
1931

2032
/**
@@ -41,8 +53,10 @@
4153
// first argument
4254

4355
P: props[vnodeFlag] // If the props argument is a renderable VNode,
44-
&& children.unshift(props) && {C: children} // ... prepend it to the children
45-
|| (props.C = children) && props // ... otherwise append 'C' to the property
56+
? {C: [].concat(props, ...children)} // ... prepend it to the children
57+
: (props.C = [].concat(...children)) && props // ... otherwise append 'C' to the property
58+
// the .concat ensures that arrays of children
59+
// will be flattened into a single array.
4660
})
4761

4862
/**
@@ -140,25 +154,18 @@
140154
? _new_dom.data = vnode // - String nodes update only the text
141155
: Object.keys(vnode.P).map( // - Element nodes have properties
142156
(
143-
key, // 1. The property name
144-
145-
_unused2, // 2. Index is unused
146-
_unused3, // 3. Array is unused
147-
148-
_value=vnode.P[key] // a. We cache the property value
149-
157+
key // 1. The property name
150158
) =>
151159

152160
key == 'style' ? // The 'style' property is an object and must be
153161
// applied recursively.
154162
Object.assign(
155163
_new_dom[key], // '[key]' is shorter than '.style'
156-
_value
164+
vnode.P[key]
157165
)
158166

159-
: (key != 'C' && // 'C' is the children, so we skip it
160-
161-
(_new_dom[key] = _value)) // All properties are applied directly to DOM
167+
: (_new_dom[key] !== vnode.P[key] && // All properties are applied directly to DOM, as
168+
(_new_dom[key] = vnode.P[key])) // long as they are different than ther value in the
162169
// instance. This includes `onXXX` event handlers.
163170

164171
) &&
@@ -214,8 +221,8 @@
214221
global.H = new Proxy(
215222
createElement,
216223
{
217-
get: (_unused4, tagName) =>
218-
wrapClassProxy(
224+
get: (targetFn, tagName) =>
225+
targetFn[tagName] || wrapClassProxy(
219226
createElement.bind(global, tagName)
220227
)
221228
}

0 commit comments

Comments
 (0)